JPA 2 Criteria API - Exception converting JPQL to Criteria API query with Eclipselink

筅森魡賤 提交于 2019-12-11 15:02:47

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!