@Entity public class Employee implements Serializable { @Id @GeneratedValue private Long id; @Embedded private EmployeeName employeeName; // accessor omitted
Entries tagged [hibernate]
Using JPQL IN clause with composite key
TweetPosted on Sunday Oct 25, 2015 at 08:16PM in JPA
Assume we have an entity named Employee
:
And EmployeeName
:
@Embeddable public class EmployeeName implements Serializable { private String firstName; private String lastName; // accessor omitted
Using preceding entity, We want to execute following JPQL:
SELECT e FROM Employee e WHERE e.employeeName IN :employeeNames
Will it work? It works for Hibernate 4.3.11.Final but unfortunately not for EclipseLink 2.6.1.
Hibernate generates following SQL for the JPQL and the parameter of a List
contains two elements:
Hibernate: select employee0_.id as id1_0_, employee0_.firstName as firstNam2_0_, employee0_.lastName as lastName3_0_ from Employee employee0_ where employee0_.firstName=? and employee0_.lastName=? or employee0_.firstName=? and employee0_.lastName=? [Employee{id=1, employeeName=EmployeeName{firstName='Scott', lastName='Vogel'}}, Employee{id=2, employeeName=EmployeeName{firstName='Nick', lastName='Jett'}}]
EclipseLink failed to generate correct SQL for the JPQL. In such case, you need to create a JPQL by hand or Criteria API that uses each column separately (lastName
and firstName
). EclipseLink produces following Exception:
Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLDataException: An attempt was made to get a data value of type 'BIGINT' from a data value of type 'entity.EmployeeName'. Error Code: 20000 Call: SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN (?,?)) bind => [EmployeeName{firstName='Scott', lastName='Vogel'}, EmployeeName{firstName='Nick', lastName='Jett'}] Query: ReadAllQuery(referenceClass=Employee sql="SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN ?)") at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:382) at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:260) at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:473) at main.Main.main(Main.java:45) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLDataException: An attempt was made to get a data value of type 'BIGINT' from a data value of type 'entity.EmployeeName'. Error Code: 20000 Call: SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN (?,?)) bind => [EmployeeName{firstName='Scott', lastName='Vogel'}, EmployeeName{firstName='Nick', lastName='Jett'}] Query: ReadAllQuery(referenceClass=Employee sql="SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN ?)") at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340) at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:684) at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:560) at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2055) at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570) at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:258) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2740) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2693) at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:559) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1175) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134) at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:460) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1222) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804) at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258) ... 7 more
Complete source code that has been used in the test can be obtained from https://github.com/lbtc-xxx/jpa-composite-in
Tags: eclipselink hibernate jpa jpql
Using JPA 2.1 AttributeConverter against Java8 LocalDate / LocalDateTime
TweetPosted on Tuesday Mar 17, 2015 at 01:50PM in JPA
I created an example project using https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa which ran on WildFly 8.2.0.Final (Hibernate 4.3.7) and H2 / Apache Derby database.
the whole project can be obtained from https://github.com/lbtc-xxx/jpa21converter .
You don’t need to define any additional configuration in persistence.xml
if you use converters in EE environment. it goes like this:
The converter for LocalDate between DATE
@Converter(autoApply = true) public class MyLocalDateConverter implements AttributeConverter<java.time.LocalDate, java.sql.Date> { @Override public java.sql.Date convertToDatabaseColumn(java.time.LocalDate attribute) { return attribute == null ? null : java.sql.Date.valueOf(attribute); } @Override public java.time.LocalDate convertToEntityAttribute(java.sql.Date dbData) { return dbData == null ? null : dbData.toLocalDate(); } }
The converter for LocalDateTime between TIMESTAMP
@Converter(autoApply = true) public class MyLocalDateTimeConverter implements AttributeConverter<java.time.LocalDateTime, java.sql.Timestamp> { @Override public java.sql.Timestamp convertToDatabaseColumn(java.time.LocalDateTime attribute) { return attribute == null ? null : java.sql.Timestamp.valueOf(attribute); } @Override public java.time.LocalDateTime convertToEntityAttribute(java.sql.Timestamp dbData) { return dbData == null ? null : dbData.toLocalDateTime(); } }
Entity class
@Entity public class MySimpleTable implements Serializable { @Id @GeneratedValue private Long id; private java.time.LocalDateTime someLocalDateTime; private java.time.LocalDate someLocalDate; ...
Hibernate produces the DDL against H2 as follows:
create table MySimpleTable ( id bigint not null, someLocalDate date, someLocalDateTime timestamp, primary key (id) )
Using converters with @EmbeddedId
Converters doesn’t work with fields that annotated as @Id
(see http://stackoverflow.com/questions/28337798/hibernate-fails-to-load-jpa-2-1-converter-when-loaded-with-spring-boot-and-sprin ) but works with @EmbeddedId
class.
Entity class:
@Entity public class MyCompositeKeyTable implements Serializable { @EmbeddedId private MyCompositeKeyEmbeddable key; ...
Embeddable class:
@Embeddable public class MyCompositeKeyEmbeddable implements Serializable { @Column(nullable = false) private java.time.LocalDateTime someLocalDateTime; @Column(nullable = false) private java.time.LocalDate someLocalDate; ...
Produced DDL:
create table MyCompositeKeyTable ( someLocalDate date not null, someLocalDateTime timestamp not null, primary key (someLocalDate, someLocalDateTime) )