Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
264 views
in Technique[技术] by (71.8m points)

java - MultipleBagFetchException thrown by Hibernate

I want to have an option in my repository layer to eager load entites, so I tried adding a method that should eager load a question entity with all the relationships, but it throws MultipleBagFetchException. How can I fix this? I am using Hibernate 4.16.

@NamedQuery(name = Question.FIND_BY_ID_EAGER, query = "SELECT q FROM Question q LEFT JOIN FETCH q.answers LEFT JOIN FETCH q.categories LEFT JOIN FETCH q.feedback LEFT JOIN FETCH q.participant WHERE q.id = :id"),

How do I get a question object which is initially lazy loaded, to be eager loaded with all relations?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is a rather nasty problem in Hibernate and actually ORM in general.

What happens is that the many (fetch) joins cause a rather large cartesian product to be created. I.e for ever other join new columns and new rows appear in the result, leading to a (fairly) large 'square' result.

Hibernate needs to distill a graph from this table, but it's not smart enough to match the right columns to the right entities.

E.g.

Suppose we have the result

A B C
A B D

Which needs to become:

 A
 |
 B
 /
C  D

Hibernate could deduct from the primary keys and some encoding magic, what the graph must be, but in practice it needs explicit help to pull this off.

One way to do this is by specifying the Hibernate specific @IndexColumn or the JPA standard @OrderColumn on the relations.

E.g.

@Entity
public class Question {


    @ManyToMany
    @JoinTable(
        name = "question_to_answer",
        joinColumns = @JoinColumn(name = "question_id"),
        inverseJoinColumns = @JoinColumn(name = "answer_id")
    )
    @IndexColumn(name = "answer_order")
    private List<Answer> answers;

    // ...
}

In this example I'm using a join table, with an extra column answer_order. Via this column, which has a unique sequential number per Question/Answer relation, Hibernate can distinguish the entries in the result table and create the required Object graph.

One note btw, if it concerns more than a few entities, using so many eager joins can potentially lead to a much larger result set than you might think based on the number of entities involved.

Further reading:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...