
<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.0 </version> </dependency> java.time.LocalDatejava.time.LocalTimejava.time.LocalDateTimejava.time.OffsetTimejava.time.OffsetDateTimejava.util.Date and java.sql.Timestamp . Therefore, you need to use the converter to convert the date stored in the database into the old design, which is supported by the JPA 2.1 version, and then convert to the updated Date and Time API for use in the application. The date converter to JPA 2.1, capable of such a conversion, may look something like the one shown in Listing 1. The converter in it is used to convert between LocalDate and java.util.Date . @Converter(autoApply = true) public class LocalDateTimeConverter implements AttributeConverter<LocalDate, Date> { @Override public Date convertToDatabaseColumn(LocalDate entityValue) { LocalTime time = LocalTime.now(); Instant instant = time.atDate(entityValue) .atZone(ZoneId.systemDefault()) .toInstant(); return Date.from(instant); } @Override public LocalDate convertToEntityAttribute(Date databaseValue){ Instant instant = Instant.ofEpochMilli(databaseValue.getTime()); return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate(); } } @Temporal code, because type mapping happens automatically. public class Job implements Serializable { . . . @Column(name = "WORK_DATE") private LocalDate workDate; . . . } @Temporal annotation should be described in all permanent fields and properties such as java.util.Date and java.util.Calendar .LocalDateTime to ZonedDateTime . The biggest problem in writing such a converter is to determine how best to convert between different types. To make things even easier, attribute converters can now be implemented. I will give an example implementation below.LocalDateTime to ZonedDateTime . @Converter public class LocalToZonedConverter implements AttributeConverter<ZonedDateTime, LocalDateTime> { @Override public LocalDateTime convertToDatabaseColumn(ZonedDateTime entityValue) { return entityValue.toLocalDateTime(); } @Override public ZonedDateTime convertToEntityAttribute(LocalDateTime databaseValue) { return ZonedDateTime.of(databaseValue, ZoneId.systemDefault()); } } ZonedDateTime contains methods that are easy to convert. The conversion is done by calling the toLocalDateTime() method. The inverse transform can be performed by calling the ZonedDateTimeOf() method and passing the LocalDateTime value along with ZoneId for use by the time zone.javax.persistence.AttributeConverter interface by passing X and Y values. The X value corresponds to the data type in the Java object, and the Y value must match the column type of the database. Then, the converter class should be annotated with @Converter . Finally, the class must override the convertToDatabaseColumn() and convertToEntityAttribute() methods. An implementation in each of these methods should convert values from certain types and back to them.@Converter(autoApply=true) . To apply a converter to a single attribute, use the @Converter annotation at the attribute level, as shown here: @Convert(converter=LocalDateConverter.java) private LocalDate workDate; @Convert(attributeName="workDate", converter = LocalDateConverter.class) public class Job implements Serializable { . . . creditLimit field of the Customer entity when it is saved. To implement such a process, the values must be encrypted before being saved and decrypted after being extracted from the database. This can be done with a converter and, using JPA 2.2, I can embed an encryption object in the converter to achieve the desired result. Listing 3 is an example. @Converter public class CreditLimitConverter implements AttributeConverter<BigDecimal, BigDecimal> { @Inject CreditLimitEncryptor encryptor; @Override public BigDecimal convertToDatabaseColumn (BigDecimal entityValue) { String encryptedFormat = encryptor.base64encode(entityValue.toString()); return BigDecimal.valueOf(Long.valueOf(encryptedFormat)); } ... } CreditLimitEncryptor class in the converter and its subsequent use to assist the process.ResultSet pagination may work better than streams.getResultStream() method was added to the Query and TypedQuery . This minor change allows JPA to simply return a result stream instead of a list. Thus, if you are working with a large ResultSet , it makes sense to compare the performance between the new implementation of the threads and the scrollable ResultSets or pagination. The reason is that the implementations of the threads extract all the records at the same time, save them to the list and then return. Scrollable ResultSet and pagination techniques extract data in parts, which may be better for large data sets.getResultStream() method getResultStream() improved implementation. Hibernate already includes a stream () method that uses a scrollable ResultSet to parse the results of records instead of returning them completely. This allows Hibernate to work with very large data sets and to do it well. Other providers can be expected to override this method to provide similar features that benefit JPA.Job entity and return the stream. First, let's take a look at the following code, where I simply analyze the stream of Jobs for a specific Customer , calling the Query getResultStream() interface method. Then, I use this stream to output the details regarding the customer and work date Job'a. public void findByCustomer(PoolCustomer customer){ Stream<Job> jobList = em.createQuery("select object(o) from Job o " + "where o.customer = :customer") .setParameter("customer", customer) .getResultStream(); jobList.map(j -> j.getCustomerId() + " ordered job " + j.getId() + " - Starting " + j.getWorkDate()) .forEach(jm -> System.out.println(jm)); } Collectors .toList() method as follows. public List<Job> findByCustomer(PoolCustomer customer){ Stream<Job> jobList = em.createQuery( "select object(o) from Job o " + "where o.customerId = :customer") .setParameter("customer", customer) .getResultStream(); return jobList.collect(Collectors.toList()); } List tasks related to pools of a particular form. In this case, I return all tasks that match the form submitted as a string. Similar to the first example, first I return a stream of Jobs records. Then, I filter the records based on the form of the customer pool. As you can see, the resulting code is very compact and easy to read. public List<Job> findByCustPoolShape(String poolShape){ Stream<Job> jobstream = em.createQuery( "select object(o) from Job o") .getResultStream(); return jobstream.filter( c -> poolShape.equals(c.getCustomerId().getPoolId().getShape())) .collect(Collectors.toList()); } @SqlResultSetMapping annotation for a given entity class. In such situations, when re-annotation support is required, container annotation should be used. Repeated annotations not only reduce the requirement to wrap collections of identical annotations in a container annotation, but can also make the code easier to read.@Repeatable meta-annotation to indicate that it can be used more than once. The @Repeatable meta annotation accepts a container annotation class type. For example, the NamedQuery annotation NamedQuery now marked with an @Repeatable(NamedQueries.class) annotation. In this case, the container annotation is still used, but you don’t have to think about it when using the same annotation on the declaration or class, because @Repeatable abstracts this part.@NamedQuery annotation to an entity class in JPA 2.1, you need to encapsulate them inside the @NamedQueries annotation, as shown in Listing 4. @Entity @Table(name = "CUSTOMER") @XmlRootElement @NamedQueries({ @NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c") , @NamedQuery(name = "Customer.findByCustomerId", query = "SELECT c FROM Customer c " + "WHERE c.customerId = :customerId") , @NamedQuery(name = "Customer.findByName", query = "SELECT c FROM Customer c " + "WHERE c.name = :name") . . .)}) public class Customer implements Serializable { . . . } @NamedQuery is a repeating annotation, it may appear in the entity class more than once, as shown in Listing 5. @Entity @Table(name = "CUSTOMER") @XmlRootElement @NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c") @NamedQuery(name = "Customer.findByCustomerId", query = "SELECT c FROM Customer c " + "WHERE c.customerId = :customerId") @NamedQuery(name = "Customer.findByName", query = "SELECT c FROM Customer c " + "WHERE c.name = :name") . . . public class Customer implements Serializable { . . . } @AssociationOverride@AttributeOverride@Convert@JoinColumn@MapKeyJoinColumn@NamedEntityGraphy@NamedNativeQuery@NamedQuery@NamedStoredProcedureQuery@PersistenceContext@PersistenceUnit@PrimaryKeyJoinColumn@SecondaryTable@SqlResultSetMappingSource: https://habr.com/ru/post/423195/
All Articles