问题
I have 3 entities. Branch,Subject,Topic. Branch has list of subjects and Subject has list of topics. Also subjectList and topicList both are lazy. I want to fetch all branch including its subjects and topics in single query.
1.
@Entity
public class Branch implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@OneToMany(mappedBy = "branch")
private List<Subject> subjectList;
//Getters and Setters
}
2.
@Entity
public class Subject implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToOne()
private Branch branch;
@OneToMany(mappedBy = "subject")
private List<Topic> topicList;
//Getters and Setters
}
3.
@Entity
public class Topic implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToOne()
private Subject subject;
//Getters and Setters
}
I tried the method below but it didn't work.
@NamedEntityGraph(name="branch_subject",
attributeNodes = {
@NamedAttributeNode(value="name"),
@NamedAttributeNode(value="subjectList", subgraph = "subjectListGraph")
},
subgraphs = {
@NamedSubgraph(name="subjectListGraph",
attributeNodes = {
@NamedAttributeNode(value="name"),
@NamedAttributeNode(value = "topicList", subgraph = "topicListGraph")
}
),
@NamedSubgraph(name="topicListGraph",
attributeNodes = {
@NamedAttributeNode("name")
}
)
}
)
Also following code is used to fetch data from database, I am using JPQL as follows
EntityGraph branchEntityGraph = entityManager
.getEntityGraph("branch_subject");
Branch branch = entityManager
.createQuery("SELECT b from Branch b WHERE b.id=:ID",
Branch.class)
.setHint("javax.persistence.loadgraph", branchEntityGraph)
.setParameter("ID", branch1.getId()).getResultList().get(0);
This gives below exception
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
回答1:
Hibernate doesn't allow you to fetch multiple Bags because it would end up fetching a Cartesian Product.
You either make your collection Sets, instead of Lists and face the Cartesian Product performance issues.
If you already INNER JOIN relations, you could simply fetch from the inner-most Child up to the root and reassemble the structure afterward. This is much more efficient since the query goes like this:
select t from Topic t join t.subject s join s.branch b
The
EntityGraphBuilder
, I described in my article is very easy to be adapted to your use case.
回答2:
I guess I had some similar issue. All my Device
entities have a Transaction
object which in my case stores the datetime
and user and computer information for that particular object. Also have a DeviceType
entity that has transaction object and has a Many to one relation with my Device
entity. So Actually I had both 1 level and 2 levels of nested relations with this Transaction Entity
. I got some nested exception because of that. Using Subgraph
fixed that issue for me. Here is my NamedEntityGraphs
definition code. Hope it helps:
@NamedEntityGraphs(value = {
@NamedEntityGraph(name = "Device.AllRelations",
attributeNodes = {
@NamedAttributeNode("transaction"),
@NamedAttributeNode(value = "deviceType", subgraph = "DeviceType.Transaction")
},
subgraphs = {
@NamedSubgraph(name = "DeviceType.Transaction", attributeNodes = {
@NamedAttributeNode("transaction")
})
}
),
@NamedEntityGraph(name = "Device.TransactionOnly", attributeNodes = {
@NamedAttributeNode("transaction")
}),
})
来源:https://stackoverflow.com/questions/30479748/jpa-how-to-define-namedentitygraph-for-3-levels