问题
I'm having trouble converting a JPA query to the use the Criteria API
I have the following query that attempts to find a ServiceUser matching a passed address parameter. ServiceUser is an abstract entity with concrete subclasses Child and Adult. I'm using the joined inheritance strategy on the ServiceUser class.
Everything works fine when I call this method.
public Set<T> findByAddress(Address address) {
Query query = manager.createQuery("SELECT distinct s FROM ServiceUser AS s JOIN s.addressHistory as h where h = :address");
query.setParameter("address", address);
HashSet<T> result = new HashSet<T>();
for (Object s : query.getResultList()) {
// tClass is the runtime type of the generic session bean.
if (this.tClass.isInstance(s)) {
result.add((T) s);
}
}
return result;
}
But, if I try to replace the function with the following that uses the generated metamodel and a typedquery then I am getting an exception
public Set<T> findByAddress(Address address) {
CriteriaBuilder cb = manager.getCriteriaBuilder();
CriteriaQuery<ServiceUser> cq = cb.createQuery(ServiceUser.class);
Root<ServiceUser> su = cq.from(ServiceUser.class);
Join<ServiceUser, Address> addressHistory = su.join(ServiceUser_.addressHistory);
cq.select(su).distinct(true).where(cb.equal(addressHistory, cb.parameter(Address.class, "address")));
TypedQuery<ServiceUser> q = manager.createQuery(cq);
q.setParameter("address", address);
HashSet<T> result = new HashSet<T>();
for (ServiceUser s : q.getResultList()) {
// tClass is the runtime type of the generic session bean.
if (this.tClass.isInstance(s)) {
result.add((T) s);
}
}
return result;
}
Here is the stacktrace will Eclipslink logging. There seems to be an NulPointerException being thrown but I'm not sure why?
/**
Test : shouldBeAbleToFindChildByAddress()
uk.gov.sunderland.ccms.model.bean.ChildService.findByAddress(Address[id=1,lineOne=7,lineTwo=Camberwell Way,lineThree=Moorside,lineFour=Sunderland,postcode=SR7 3XN])
[EL Finer]: 2010-12-20 12:39:42.89--ServerSession(7055953)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--client acquired
[EL Finer]: 2010-12-20 12:39:42.89--UnitOfWork(22763294)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--TX binding to tx mgr, status=STATUS_ACTIVE
[EL Finest]: 2010-12-20 12:39:42.89--UnitOfWork(22763294)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--Execute query ReadObjectQuery(referenceClass=Address sql="SELECT ID, LINE_TWO, LINE_THREE, LINE_ONE, LINE_FOUR, POSTCODE FROM ADDRESS WHERE (ID = ?)")
[EL Finest]: 2010-12-20 12:39:42.906--UnitOfWork(22763294)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--Execute query ReadAllQuery(referenceClass=ServiceUser )
[EL Finest]: 2010-12-20 12:39:42.906--ServerSession(7055953)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--reconnecting to external connection pool
[EL Fine]: 2010-12-20 12:39:42.906--ServerSession(7055953)--Connection(32184426)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--SELECT DISTINCT t2.SERVICE_USER_TYPE FROM ADDRESS t0, SERVICE_USER t2, SERVICE_USER_ADDRESS t1 WHERE ((? = t0.ID) AND ((t1.SERVICE_USER_ID = t2.ID) AND (t0.ID = t1.ADDRESS_ID)))
bind => [1]
[EL Finer]: 2010-12-20 12:39:42.906--UnitOfWork(22763294)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--class uk.gov.sunderland.ccms.model.entity.Adult
[EL Finest]: 2010-12-20 12:39:42.906--ServerSession(7055953)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--reconnecting to external connection pool
[EL Fine]: 2010-12-20 12:39:42.906--ServerSession(7055953)--Connection(29495316)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--SELECT DISTINCT t0.ID, t0.SERVICE_USER_TYPE, t0.TITLE, t0.DOB, t0.GENDER, t0.DISABILITY, t0.ETHNICITY, t1.ID, t1.EMPLOYMENT, t1.INFO_PACK_REQUIRED, t1.HOME_PHONE, t1.OTHER_LANGUAGE, t1.REFERRER, t1.MOBILE_PHONE, t1.LONE_PARENT, t1.GP_PRACTICE, t1.CONTACTABLE, t1.WORK_PHONE, t1.BABY_DUE_DATE, t1.ENGLISH_LEVEL FROM SERVICE_USER_ADDRESS t3, ADDRESS t2, ADULT t1, SERVICE_USER t0 WHERE (((? = t2.ID) AND ((t1.ID = t0.ID) AND (t0.SERVICE_USER_TYPE = ?))) AND ((t3.SERVICE_USER_ID = t0.ID) AND (t2.ID = t3.ADDRESS_ID)))
bind => [1, 1]
[EL Warning]: 2010-12-20 12:39:42.906--UnitOfWork(22763294)--Thread(Thread[pool-52-thread-1,5,grizzly-kernel])--java.lang.NullPointerException
at org.eclipse.persistence.descriptors.InheritancePolicy.selectAllRowUsingDefaultMultipleTableSubclassRead(InheritancePolicy.java:1355)
at org.eclipse.persistence.descriptors.InheritancePolicy.selectAllRowUsingMultipleTableSubclassRead(InheritancePolicy.java:1396)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2493)
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:407)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1074)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:736)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1034)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:380)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1112)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2909)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1291)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1273)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1247)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:479)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:714)
*/
Looking at the sql that gets issued with the failing criteria api query and comparing with the sql that gets issued when I perform the query with the jpa string query.
Criteria Query
SELECT DISTINCT t0.ID, t0.SERVICE_USER_TYPE, t0.TITLE, t0.DOB, t0.GENDER, t0.DISABILITY, t0.ETHNICITY, t1.ID, t1.EMPLOYMENT, t1.INFO_PACK_REQUIRED, t1.HOME_PHONE, t1.OTHER_LANGUAGE, t1.REFERRER, t1.MOBILE_PHONE, t1.LONE_PARENT, t1.GP_PRACTICE, t1.CONTACTABLE, t1.WORK_PHONE, t1.BABY_DUE_DATE, t1.ENGLISH_LEVEL
FROM SERVICE_USER_ADDRESS t3, ADDRESS t2, ADULT t1, SERVICE_USER t0
WHERE (((? = t2.ID) AND ((t1.ID = t0.ID) AND (t0.SERVICE_USER_TYPE = ?)))
AND ((t3.SERVICE_USER_ID = t0.ID) AND (t2.ID = t3.ADDRESS_ID)))
JPA String Query
SELECT DISTINCT t0.ID, t0.SERVICE_USER_TYPE, t0.TITLE, t0.DOB, t0.GENDER, t0.DISABILITY, t0.ETHNICITY, t1.ID, t1.EMPLOYMENT, t1.INFO_PACK_REQUIRED, t1.HOME_PHONE, t1.OTHER_LANGUAGE, t1.REFERRER, t1.MOBILE_PHONE, t1.LONE_PARENT, t1.GP_PRACTICE, t1.CONTACTABLE, t1.WORK_PHONE, t1.BABY_DUE_DATE, t1.ENGLISH_LEVEL
FROM SERVICE_USER_ADDRESS t3, ADDRESS t2, ADULT t1, SERVICE_USER t0
WHERE (((? = t2.ID) AND ((t1.ID = t0.ID) AND (t0.SERVICE_USER_TYPE = ?)))
AND ((t3.SERVICE_USER_ID = t0.ID) AND (t2.ID = t3.ADDRESS_ID)))
and
SELECT DISTINCT t0.ID, t0.SERVICE_USER_TYPE, t0.TITLE, t0.DOB, t0.GENDER, t0.DISABILITY, t0.ETHNICITY, t1.ID
FROM SERVICE_USER_ADDRESS t3, ADDRESS t2, CHILD t1, SERVICE_USER t0 WHERE (((? = t2.ID) AND ((t1.ID = t0.ID) AND (t0.SERVICE_USER_TYPE = ?))) AND ((t3.SERVICE_USER_ID = t0.ID) AND (t2.ID = t3.ADDRESS_ID)))
I can see that the first part that deals with the Adult subclass of ServiceUser is identical in both cases but when it comes to the Child subclass the Criteria query throws
[EL Warning]: 2010-12-20 )--java.lang.NullPointerException
at org.eclipse.persistence.descriptors.InheritancePolicy.selectAllRowUsingDefaultMultipleTableSubclassRead(InheritancePolicy.java:1355)
Could this be a bug with Eclipselink?
回答1:
Yes this indeed appears to be a bug with Eclipselink
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
Changing the inheritance strategy from
@Inheritance(strategy = InheritanceType.JOINED)
to
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
on the abstract base class SERVICE_USER provides a workaround that in my case is ok.
来源:https://stackoverflow.com/questions/4489776/jpa-2-criteria-api-exception-converting-jpql-to-criteria-api-query-with-eclips