我们有一个项目,我们需要懒惰地加载一个实体的集合,但在某些情况下我们需要它们急切地加载它们。我们在实体中添加了@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<Comment> comments;
@ElementCollection
@CollectionTable(name="post_plusoners")
private List<PostRelatedPerson> plusoners;
@ElementCollection
@CollectionTable(name="post_shared_with")
private List<PostRelatedPerson> sharedWith;
}
查询方法(所有人都挤在一起让它可以发布):
@Override
public Page<Post> findFullPosts(Specification<Post> spec, Pageable pageable) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Post> query = builder.createQuery(Post.class);
Root<Post> post = query.from(Post.class);
Predicate postsPredicate = spec.toPredicate(post, query, builder);
query.where(postsPredicate);
EntityGraph<?> entityGraph = entityManager.createEntityGraph("PlusPost.Full");
TypedQuery<GooglePlusFullPost> 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<P> resultList = total > pageable.getOffset() ? query.getResultList() : Collections.<P>emptyList();
return new PageImpl<P>(resultList, pageable, total);
}
有关为什么在实体级别上使用热切提取,而不是使用动态实体图形的任何提示?
答案 0 :(得分:11)
我打赌你认为正在工作的渴望提取,实际上工作不正确。
当你渴望获取多个“bag”(一个允许重复的unorder集合)时,用于执行eager fetch(左外连接)的sql将为连接的关联返回多个结果,如{{3}所述}。因此,当你有多个org.hibernate.loader.MultipleBagFetchException
急切地获取时,hibernate不会抛出List
,但由于上面给出的原因,它不会返回准确的结果。
但是,当你给查询提供实体图提示时,hibernate会(正确地)抱怨。 SO answer:
急切提取本身不是问题,在一个SQL查询中使用多个连接是。它不仅限于静态提取策略;它从未被支持(属性),因为它在概念上是不可能的。
Hibernate developer, Emmanuel Bernard, addresses the reasons for this exception to be thrown那个,
“非索引”列表或原始集合的大多数用法都是错误的,并且在语义上应该是集合。
如此底线,为了让多个渴望的提取按你的意愿工作:
Set
而不是List
List
注释保留@OrderColumn
索引,FetchMode.SELECT
或FetchMode.SUBSELECT
)修改强>
相关: