NamedEntityGraph – JPA / Hibernate抛出org.hibernate.loader.MultipleBagFetchException:无法同时获取多个包

我们有一个项目,我们需要懒惰地加载一个实体的集合,但在某些情况下,我们需要它们急切地加载它们。 我们在实体中添加了@NamedEntityGraph注释。 在我们的存储库方法中,我们添加了一个“javax.persistence.loadgraph”提示,以急切地加载在所述注释中定义的4个属性。 当我们调用该查询时,Hibernate会抛出org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

有趣的是,当我将所有这些集合重新定义为急切获取时,Hibernate 在没有MultipleBagFetchException的情况下急切地获取它们

这是蒸馏代码。 实体:

 @Entity @NamedEntityGraph(name = "Post.Full", attributeNodes = { @NamedAttributeNode("comments"), @NamedAttributeNode("plusoners"), @NamedAttributeNode("sharedWith") } ) public class Post { @OneToMany(cascade = CascadeType.ALL, mappedBy = "postId") private List comments; @ElementCollection @CollectionTable(name="post_plusoners") private List plusoners; @ElementCollection @CollectionTable(name="post_shared_with") private List sharedWith; } 

查询方法(所有人都挤在一起使其可用):

 @Override public Page findFullPosts(Specification spec, Pageable pageable) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(Post.class); Root post = query.from(Post.class); Predicate postsPredicate = spec.toPredicate(post, query, builder); query.where(postsPredicate); EntityGraph entityGraph = entityManager.createEntityGraph("PlusPost.Full"); TypedQuery typedQuery = entityManager.createQuery(query); typedQuery.setHint("javax.persistence.loadgraph", entityGraph); query.setFirstResult(pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); Long total = QueryUtils.executeCountQuery(getPostCountQuery(specification)); List

resultList = total > pageable.getOffset() ? query.getResultList() : Collections.

emptyList(); return new PageImpl

(resultList, pageable, total); }

有关为什么在实体级别上使用热切提取而不是动态实体图形的任何提示?

我打赌你认为工作的热切提取,实际上工作不正确。

当你渴望获取多个“bag”(一个允许重复的unorder集合)时,用于执行eager fetch(左外连接)的sql将返回连接关联的多个结果,如本SO答案所解释的。 因此,当你急切地获取多个List时,hibernate不会抛出org.hibernate.loader.MultipleBagFetchException ,但由于上面给出的原因,它不会返回准确的结果。

但是,当你给查询提供实体图提示时,hibernate会(正确地)抱怨。 Hibernate开发人员Emmanuel Bernard解决了抛出此exception的原因 :

渴望获取本身不是问题,在一个SQL查询中使用多个连接是。 它不仅限于静态抓取策略; 它从未被支持(属性),因为它在概念上是不可能的。

Emmanuel继续在另一个JIRA评论中说,

“非索引”List或raw Collection的大多数用法都是错误的,并且在语义上应该是Sets。

所以底线,为了得到多个渴望的提取工作,你想要的:

  • 使用Set而不是List
  • 使用JPA 2的@OrderColumn注释保留List索引,
  • 如果所有其他方法都失败了,则回FetchMode.SELECT Hibernate特定的提取注释( FetchMode.SELECTFetchMode.SUBSELECT

编辑

有关: