JPA:如何为3个级别定义@NamedEntityGraph? [英] JPA : How to define @NamedEntityGraph for 3 levels?

查看:2904
本文介绍了JPA:如何为3个级别定义@NamedEntityGraph?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3个实体。分公司,主题,话题。
分支有主题列表,主题有主题列表。另外
subjectList和topicList都是懒惰的。我想在单个查询中获取所有分支
,包括其主题和主题。

<1>


 @Entity 
public class Branch implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
私人字符串名称;

@OneToMany(mappedBy =branch)
private List< Subject> subjectList;
// Getters and Setters
}

2。

  @Entity 
public class Subject实现Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

私人字符串名称;

@ManyToOne()
私人分支分支;

@OneToMany(mappedBy =subject)
private List< Topic>题目列表;
// Getters and Setters
}

3。

  @Entity 
public class Topic实现Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
私人字符串名称;

@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 = entityMa nager 
.getEntityGraph(branch_subject);

分支分支= entityManager
.createQuery(从分支b中选择b在WHERE b.id =:ID,
Branch.class)
.setHint( javax.persistence.loadgraph,branchEntityGraph)
.setParameter(ID,branch1.getId())。getResultList()。get(0);

这给出了下面的异常

  org.hibernate.loader.MultipleBagFetchException:无法同时获取多个包


解决方案

Hibernate不允许你提取多个Bag,因为它最终会获取Cartesian产品。


  1. 您可以制作您的集合集合,而不是列表

    a>并且面对Cartesian产品性能问题。
  2. 如果您已经是INNER JOIN关系,您可以简单地从最内层的Child获取根目录,然后重新组装结构。这是更有效的,因为查询是这样的:

      select t 
    from Topic t
    join t.subject s
    join s.branch b

    EntityGraphBuilder ,我在我的文章中描述的非常容易适应您的使用情况。


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 have tried below method but it not working.

@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

解决方案

Hibernate doesn't allow you to fetch multiple Bags because it would end up fetching a Cartesian Product.

  1. You either make your collection Sets, instead of Lists and face the Cartesian Product performance issues.

  2. 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.

这篇关于JPA:如何为3个级别定义@NamedEntityGraph?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆