java - NamedEntityGraph - JPA/Hibernate 抛出 org.hibernate.loader.MultipleBagFetchException : cannot simultaneously fetch multiple bags

标签 java hibernate jpa

我们有一个项目需要延迟加载实体的集合,但在某些情况下我们需要急切加载它们。我们为我们的实体添加了一个 @NamedEntityGraph 注释。在我们的存储库方法中,我们添加了一个“javax.persistence.loadgraph”提示以急切地加载在所述注释中定义的 4 个属性。当我们调用该查询时,Hibernate 抛出 org.hibernate.loader.MultipleBagFetchException: cannot simultaneous 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);
}

关于为什么这适用于实体级别的预取,但不适用于动态实体图,有什么提示吗?

最佳答案

我敢打赌,您认为有效的急切获取实际上工作不正常。

当您渴望获取多个“包”(允许重复的无序集合)时,用于执行渴望获取(左外连接)的 sql 将为连接的关联返回多个结果,如此 SO answer 所述。 .因此,当您急切地获取多个 List 时,hibernate 不会抛出 org.hibernate.loader.MultipleBagFetchException,但由于上述原因,它不会返回准确的结果。

但是,当您为查询提供实体图提示时,hibernate 会(正确地)提示。 Hibernate developer, Emmanuel Bernard, addresses the reasons for this exception to be thrown :

eager fetching is not the problem per se, using multiple joins in one SQL query is. It's not limited to the static fetching strategy; it has never been supported (property), because it's conceptually not possible.

Emmanuel goes on to say in a different JIRA comment那个,

most uses of "non-indexed" List or raw Collection are erroneous and should semantically be Sets.

所以最重要的是,为了让多个急切的抓取按照你的意愿工作:

  • 使用 Set 而不是 List
  • 使用 JPA 2 的 @OrderColumn 注释保留 List 索引,
  • 如果一切都失败了,回退到 Hibernate 特定的提取注释(FetchMode.SELECTFetchMode.SUBSELECT)

编辑

相关:

关于java - NamedEntityGraph - JPA/Hibernate 抛出 org.hibernate.loader.MultipleBagFetchException : cannot simultaneously fetch multiple bags,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26934011/

相关文章:

java - 确定 JOIN 是否产生任何列

java - OOP 设计 - 创建策略/模式

java - Hibernate + Spring 异常 : Unknown Entity

java - 加载实体而不锁定数据库中的行

mysql - 无法从类型 [java.lang.Object[]] 转换为类型 [@org.springframework.data.jpa.repository.Query

java - 如何在eclipselink中访问多个租户?

java - .Contains() 方法不调用 Overridden equals 方法

java - 更新后 TestNG 未能通过大多数测试

java - hibernate : "ClassNotFoundException: javax.persistence.spi.ProviderUtil"

java - Hibernate 用户和 friend JsonReference