当前位置: 首页 > 知识库问答 >
问题:

如何在一个JPQL查询中使用多个连接提取

关玄裳
2023-03-14

我有以下实体:

public class Category {
   private Integer id;

   @OneToMany(mappedBy = "parent")
   private List<Topic> topics;
}

public class Topic {
   private Integer id;

   @OneToMany(mappedBy = "parent")
   private List<Posts> posts;

   @ManyToOne
   @JoinColumn(name = "id")
   private Category parent;
}

public class Post {
   private Integer id;

   @ManyToOne
   @JoinColumn(name = "id")
   private Topic parent;
   /* Post fields */
}
SELECT c FROM Category c
JOIN FETCH c.topics t
JOIN FETCH t.posts p WHERE 
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

在一个查询中完成是可能的?

共有1个答案

周翰
2023-03-14

考虑到我们有以下实体:

并且,您希望获取一些父post实体以及所有关联的注释标记集合。

如果使用多个join fetch指令:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    left join fetch p.tags
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags [
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.comments,
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.tags
]

您可以执行以下技巧:

List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.tags t
    where p in :posts
    """, Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

在第一个JPQL查询中,distinct不转到SQL语句。这就是为什么我们将pass_distinct_throughJPA查询提示设置为false

DISTINCT在JPQL中有两个含义,在这里,我们需要它在Java端而不是SQL端删除GetResultList返回的Java对象引用。

避免FetchType.Eager,不要从List切换到Set,因为这样做会使Hibernate隐藏MultipleBagFetchException。每次只取一个收藏品,你就没事了。

只要使用与要初始化的集合数量相同的查询,就可以了。只是不要在循环中初始化集合,因为这将触发n+1查询问题,这也不利于性能。

 类似资料:
  • 问题内容: 我有以下实体: 而且我想使用JPQL查询来获取包含已加入主题和已加入帖子的所有类别。我被写成如下查询: 但是我得到了错误 我找到了有关此错误的文章,但这些文章仅描述了在一个实体中有两个要加入的集合的情况。我的问题有点不同,我不知道如何解决。 是否可以在一个查询中执行? 对不起,我的英语不好,但我通常会说其他语言 问题答案: 您可以使用Child-Parent提取策略,并根据结果重新组合

  • 我将编写此查询,它在Console中工作。sql或Workbench中,但当我在@Query中使用它时,我得到了一个语法错误! 在我的IDE中,错误是在下次选择

  • 我有2个具有多对多关系的实体User和AcCountBase。我需要从连接表中选择所有具有选定用户ID的AcCountBase对象。我尝试了一些连接查询,但不起作用。

  • 我有一个查询来确定一个值是否已经存在于数据库中。在将资源插入数据库之前,我用它来验证资源。看起来是这样的: 在数据访问上,实现如下: 它确实有效并完成工作,但是我认为query.getResultList(.isEmpty()不是我需要的正确语法,而且我希望让它更快,并在找到值后返回,而不是循环遍历数据库上的每一行。任何建议将不胜感激。

  • 问题内容: 我有以下查询: 所以我正在使用并抓住。所以现在,我要获取该image_id并将其从图像表中转换成。 如何将其添加到查询中? 问题答案: 您可以简单地添加另一个联接,如下所示: 但是请注意,由于它是一个,如果您的消息中没有图像,则将跳过整个行。如果可能的话,您可能需要执行一次操作,该操作将仅在存在一个仪表板消息的情况下返回所有仪表板消息和一个image_filename(否则,您将获得n

  • 我有两个域对象,如下所示 使用者Java语言 产品Java语言 在这种情况下,用户到产品具有多对一关系。多个用户可以订阅同一产品。我想通过连接这两个表来查询User表中的用户电子邮件ID,其中productId是产品表中的主键,foriegn键是User表中的foriegn键...如何使用Hibernate查询语言或标准通过连接这两个表来做到这一点?