Community
Participate
Working Groups
Build Identifier: Trunk If you combine QueryHints.FETCH_GROUP_LOAD and QueryHints.BATCH you will get this NPE: java.lang.NullPointerException at org.eclipse.persistence.internal.sessions.AbstractSession$1.iterate(AbstractSession.java:4076) at org.eclipse.persistence.internal.descriptors.DescriptorIterator.startIterationOn(DescriptorIterator.java:666) at org.eclipse.persistence.internal.sessions.AbstractSession.load(AbstractSession.java:4105) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1087) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:768) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1038) at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:383) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1116) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2943) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1301) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1283) at org.eclipse.persistence.mappings.CollectionMapping.executeBatchQuery(CollectionMapping.java:842) at org.eclipse.persistence.mappings.ForeignReferenceMapping.extractResultFromBatchQuery(ForeignReferenceMapping.java:503) at org.eclipse.persistence.mappings.CollectionMapping.extractResultFromBatchQuery(CollectionMapping.java:823) at org.eclipse.persistence.internal.indirection.BatchValueHolder.instantiate(BatchValueHolder.java:55) at org.eclipse.persistence.internal.indirection.QueryBasedValueHolder.instantiate(QueryBasedValueHolder.java:75) at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:84) at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:160) at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:220) at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:84) at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:237) at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:397) at org.eclipse.persistence.indirection.IndirectList.size(IndirectList.java:726) at org.eclipse.persistence.internal.queries.CollectionContainerPolicy.sizeFor(CollectionContainerPolicy.java:177) at org.eclipse.persistence.internal.indirection.TransparentIndirectionPolicy.instantiateObject(TransparentIndirectionPolicy.java:363) at org.eclipse.persistence.mappings.ForeignReferenceMapping.instantiateAttribute(ForeignReferenceMapping.java:914) at org.eclipse.persistence.internal.sessions.AbstractSession$1.iterate(AbstractSession.java:4090) at org.eclipse.persistence.internal.descriptors.DescriptorIterator.startIterationOn(DescriptorIterator.java:666) at org.eclipse.persistence.internal.sessions.AbstractSession.load(AbstractSession.java:4102) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1087) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:768) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1038) at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:383) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1116) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2943) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1301) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1283) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1257) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:479) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:714) at user.test.BatchFetchTest.queryWithEagerBatchFetch(BatchFetchTest.java:98) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Source is: EntityManager em = emf.createEntityManager(); FetchGroup childFG = new FetchGroup(); childFG.addAttribute("name"); FetchGroup parentFG = new FetchGroup(); parentFG.addAttribute("name"); parentFG.addAttribute("children", childFG); // parentFG.setShouldLoadAll(true); TypedQuery<Parent> query = em.createQuery("select p from Parent p", Parent.class); query.setHint(QueryHints.FETCH_GROUP, parentFG); query.setHint(QueryHints.FETCH_GROUP_LOAD, HintValues.TRUE); query.setHint(QueryHints.BATCH, "p.children"); List<Parent> parents = query.getResultList(); Reproducible: Always Steps to Reproduce: A JUnit test case will be provided shortly
Created attachment 179180 [details] testcase A JUnit test case
Created attachment 179181 [details] proposed patch
Created attachment 179276 [details] updated patch The updated patch fixes the same flaw as the original patch, but in a different place: AbstractSession#load should not be passed ComplexQueryResult, it's responsibility of the query to handle ComplexResultQuery case and extract the actual result from it to pass to load method. Added a test new simpleFetchGroupLoadWithBatch test case to both fieldaccess.fetchgroups.NestedFetchGroupTests and fetchgroups.NestedFetchGroupTests. Apart from verifying that NPE is no longer thrown the test case verifies that all the loading is done during query.getResultList. The test case is (almost) exact copy of the one suggested by Frank in e-mail: Frank Schwarz wrote: > > > > Hi, > > > > I've been investigating the new fetch-group feature(s) of EL 2.1.0 and > > there is something I'd like to understand: > > > > Lets say you have got "Employee" -- "Project" (many to many) > > > > FetchGroup projectGroup = new FetchGroup(); > > projectGroup.addAttribute("name"); > > > > FetchGroup employeeGroup = new FetchGroup(); > > employeeGroup.addAttribute("id"); > > employeeGroup.addAttribute("name"); > > employeeGroup.addAttribute("projects", projectGroup); > > > > TypedQuery<Employee> query = em.createQuery("select e from ...", > > Employee.class); > > query.setHint(QueryHints.FETCH_GROUP, employeeGroup); > > query.setHint(QueryHints.BATCH, "e.projects"); > > > > List<Employee> emps = query.getResultList(); // (1) > > for (Employee e : emps) { > > e.getProjekte().size(); // (2) > > } > > > > You can observe two sql statements. This first one at position (1) to load > > all employees and the second one at position (2) to load all projects of > > all previously loaded employees. > > > > I would have expected the second sql statement to occur also at position > > (1). I thought that this fetch plan was saying: Please ensure that all > > employees and all their projects are loaded when you return from > > "getResultList() and load all projects with a separate batch statement." > > > > Would the following statement change the behavior to the one I am > > expecting?: > > > > employeeGroup.setShouldLoadAll(true); > > > > And, is batch fetching compatible with this setting? > > > > > > Thank you for your help, > > Frank > > > > > > PS: It is currently not possible to simply test it, as it will raise a NPE > > at > > org.eclipse.persistence.internal.sessions.AbstractSession$1.iterate(AbstractSession.java:4067) > > > >
Checked into both trunk (2.2) and 2.1.2. Reviewed by James.
Moving ipLog flag to patch
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink