I was trying to fetch an entities association and have that fully initialized (will be serialized to JSON):
{code:sql}SELECT u.groups FROM User u WHERE u.id = ?1{code}
Applying a Named/Ad Hoc Fetch Graph yields an Exception. E.g. for this Graph:
{code:java}EntityGraph<Group> eg = em.createEntityGraph(Group.class); eg.addAttributeNodes("permissions");{code}
I get:
{quote}org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list \[FromElement\{explicit,collection join,fetch join,fetch non-lazy properties,classAlias=u,role=com.example.assocFetchGraph.persistence.User.permissions,tableName=\{none},tableAlias=permission3_,origin=null,columns=\{,className=null}}]{quote}
That is because both classes have a `permissions` property. Otherwise I would get an error saying the attribute was not found.
Expected behavior would be, that the Fetch Graph's attributes would be resolved relative to Group, not User. (But the JPA spec doesn't seem to be very clear here).
I have created a reproducing example: [https://github.com/cptwunderlich/assocEntityGraphMRE|https://github.com/cptwunderlich/assocEntityGraphMRE]
We had a discussion about this on Zulip #hibernate-user "EntityGraph resolution" I also created a StackOverflow question: [https://stackoverflow.com/questions/63015923/jpa-select-association-and-use-namedentitygraph|https://stackoverflow.com/questions/63015923/jpa-select-association-and-use-namedentitygraph]
I provde an excerpt of the code here for your convenience:
{code:java}@Entity public class User {
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
@Enumerated(EnumType.STRING) @ElementCollection(targetClass = Permission.class) @CollectionTable(name = "USERS_PERMISSIONS", joinColumns = @JoinColumn(name = "uid")) private Set<Permission> permissions = EnumSet.of(Permission.FOO);
@ManyToMany(fetch = FetchType.LAZY) private Set<Group> groups = new HashSet<>(); }
@Entity @NamedEntityGraph(name = Group.ENTITY_GRAPH, attributeNodes = { @NamedAttributeNode("permissions") }) public class Group { public static final String ENTITY_GRAPH = "group-with-permissions";
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
@Enumerated(EnumType.STRING) @ElementCollection(targetClass = Permission.class) @CollectionTable( name = "GROUPS_PERMISSIONS", joinColumns = @JoinColumn(name = "gid") ) private Set<Permission> permissions = EnumSet.noneOf(Permission.class); }
// Query: List res = em.createQuery("SELECT u.groups FROM User u WHERE u.id = ?1") .setParameter(1, u.getId()) .setHint(GraphSemantic.FETCH.getJpaHintName(), em.getEntityGraph(Group.ENTITY_GRAPH)) .getResultList();{code}
Stack Trace is:
{noformat}java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,collection join,fetch join,fetch non-lazy properties,classAlias=u,role=com.example.assocFetchGraph.persistence.User.permissions,tableName={none},tableAlias=permission3_,origin=null,columns={,className=null}}] [SELECT u.groups FROM com.example.assocFetchGraph.persistence.User u WHERE u.id = ?1]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542) at org.hibernate.query.Query.getResultList(Query.java:165) at com.example.assocFetchGraph.AssocFetchGraphApplicationTests.fetchAssocWithNamedFetchGraph(AssocFetchGraphApplicationTests.java:48) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248) at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211) at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) Caused by: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,collection join,fetch join,fetch non-lazy properties,classAlias=u,role=com.example.assocFetchGraph.persistence.User.permissions,tableName={none},tableAlias=permission3_,origin=null,columns={,className=null}}] [SELECT u.groups FROM com.example.assocFetchGraph.persistence.User u WHERE u.id = ?1] at org.hibernate.QueryException.generateQueryException(QueryException.java:120) at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:220) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:78) at org.hibernate.query.internal.AbstractProducedQuery.makeQueryParametersForExecution(AbstractProducedQuery.java:1372) at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1567) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1533) ... 65 more Caused by: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,collection join,fetch join,fetch non-lazy properties,classAlias=u,role=com.example.assocFetchGraph.persistence.User.permissions,tableName={none},tableAlias=permission3_,origin=null,columns={,className=null}}] at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:217) at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:1026) at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:794) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:689) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:325) at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:273) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ... 71 more{noformat}
The repository also contains a test case where I JOIN FETCH permissions and that works. Interestingly, in my actual code, I have and additional JOIN FETCH for a ManyToOne and I get the above Exception for that additional property. |
|