org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

前端 未结 7 809
南笙
南笙 2020-12-04 20:07

Following is my code Here I am using multiple lists to fetch data from database. On fetching data from hql query it is showing exception.

Pojo Class

         


        
相关标签:
7条回答
  • 2020-12-04 20:40

    Your request fetch too many data and HIbernate cannot load them all. Reduce your request and/or configure your entities to retrieve just needed data

    0 讨论(0)
  • 2020-12-04 20:45

    This is a very common question, so I decided to turn the answer into an article.

    Hibernate doesn't allow fetching more than one bag because that would generate a Cartesian product.

    Now, you will find lots of answers, blog posts, videos, or other resources telling you to use a Set instead of a List for your collections.

    That's terrible advice!

    Using Sets instead of Lists will make the MultipleBagFetchException go away, but the Cartesian Product will still be there.

    The right fix

    Instead of using multiple JOIN FETCH in a single JPQL or Criteria API query:

    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();
    

    You can do the following trick:

    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();
    

    As long as you fetch at most one collection using JOIN FETCH, you will be fine. By using multiple queries, you will avoid the Cartesian Product since any other collection but the first one is fetched using a secondary query.

    0 讨论(0)
  • 2020-12-04 20:48

    I find using @PostLoad annotated method in the entity most useful, I'd do something like

    @PostLoad
    public void loadCollections(){
         int s1 = productReplacements.size();
         int s2 = billProductList.size();
    }
    

    this way I'm able to fine control the eager loading and initialization of collections in the same transaction that loaded the entity.

    0 讨论(0)
  • 2020-12-04 20:50

    For me I had the same error and I solved by adding the annotation of hibernate @Fetch

    @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Child> childs;
    
    0 讨论(0)
  • 2020-12-04 20:53

    I used the new annotation @OrderColumn instead of @IndexColumn (deprecated see: https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/IndexColumn.html) and it works now.

    Annotate one of the collections with @OrderColumn e.g.

    @ManyToMany(cascade = CascadeType.ALL)
    @OrderColumn
    private List<AddressEntity> addresses = Lists.newArrayList();
    
    @Builder.Default
    @ManyToMany(cascade = CascadeType.ALL)
    private List<BankAccountEntity> bankAccounts = Lists.newArrayList();
    
    0 讨论(0)
  • 2020-12-04 20:55

    You can only join-fetch following one relation for an entity (either billPaidDetailses or billProductList).

    Consider using lazy associations and loading collections when they are needed, OR using lazy associations and loading collections manually with Hibernate.initialize(..). At least that was the conclusion I came to when I had a similar issue.

    Either way it will take more than one query to the database.

    0 讨论(0)
提交回复
热议问题