JPA:如何为 3 个级别定义 @NamedEntityGraph?
JPA : How to define @NamedEntityGraph for 3 levels?
我有 3 个实体。分支,主题,主题。
Branch 有主题列表,Subject 有主题列表。还
subjectList 和 topicList 都是惰性的。我想获取所有分支
在单个查询中包含其主题。
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
}
我尝试了下面的方法,但是没有用。
@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")
}
)
}
)
下面的代码也用于从
数据库,我正在使用 JPQL 如下
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);
这给出了以下例外情况
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
Hibernate 不允许您获取多个包,因为它最终会获取笛卡尔积。
M → N → P 一对多或多对多关系
对于多嵌套层次结构,您可以在多个集合上使用 JOIN FETCH
,只要您的列表映射为 Set
。
M → N 和M → P 一对多或多对多关系
对于同级集合,如 M → N 和 M → P,不要切换到使用 Set
而不是 List
。
使用 Set
而不是 List
来避免 MultipleBagFetchException
is a very bad idea since you will still end up with a Cartesian Product
,这将导致性能问题,因为您将要获取 M x N x P
记录。
在这种情况下,更好的方法是使用第一个查询获取一个集合,并对其余集合使用其他查询:
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();
此策略允许您通过获取 M x (N + P)
条记录来避免 M x N x P
结果集。
从子端获取到父端
如果在获取子集合时必须使用 INNER JOIN,那么您可以简单地[从最内层的子集合获取到根][3],然后重新组装结构。这样效率更高,因为查询是这样的:
select t
from Topic t
join t.subject s
join s.branch b
我想我遇到了类似的问题。我所有的 Device
实体都有一个 Transaction
对象,在我的例子中,该对象存储 datetime
以及该特定对象的用户和计算机信息。还有一个 DeviceType
实体,它有事务对象并且与我的 Device
实体有多对一关系。所以实际上我与这个 Transaction Entity
有 1 级和 2 级的嵌套关系。因此,我得到了一些嵌套的异常。使用 Subgraph
为我解决了这个问题。这是我的 NamedEntityGraphs
定义代码。希望对您有所帮助:
@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")
}),
})
我有 3 个实体。分支,主题,主题。 Branch 有主题列表,Subject 有主题列表。还 subjectList 和 topicList 都是惰性的。我想获取所有分支 在单个查询中包含其主题。
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
}
我尝试了下面的方法,但是没有用。
@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")
}
)
}
)
下面的代码也用于从 数据库,我正在使用 JPQL 如下
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);
这给出了以下例外情况
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
Hibernate 不允许您获取多个包,因为它最终会获取笛卡尔积。
M → N → P 一对多或多对多关系
对于多嵌套层次结构,您可以在多个集合上使用 JOIN FETCH
,只要您的列表映射为 Set
。
M → N 和M → P 一对多或多对多关系
对于同级集合,如 M → N 和 M → P,不要切换到使用 Set
而不是 List
。
使用 Set
而不是 List
来避免 MultipleBagFetchException
is a very bad idea since you will still end up with a Cartesian Product
,这将导致性能问题,因为您将要获取 M x N x P
记录。
在这种情况下,更好的方法是使用第一个查询获取一个集合,并对其余集合使用其他查询:
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();
此策略允许您通过获取 M x (N + P)
条记录来避免 M x N x P
结果集。
从子端获取到父端
如果在获取子集合时必须使用 INNER JOIN,那么您可以简单地[从最内层的子集合获取到根][3],然后重新组装结构。这样效率更高,因为查询是这样的:
select t
from Topic t
join t.subject s
join s.branch b
我想我遇到了类似的问题。我所有的 Device
实体都有一个 Transaction
对象,在我的例子中,该对象存储 datetime
以及该特定对象的用户和计算机信息。还有一个 DeviceType
实体,它有事务对象并且与我的 Device
实体有多对一关系。所以实际上我与这个 Transaction Entity
有 1 级和 2 级的嵌套关系。因此,我得到了一些嵌套的异常。使用 Subgraph
为我解决了这个问题。这是我的 NamedEntityGraphs
定义代码。希望对您有所帮助:
@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")
}),
})