JPA : How to define @NamedEntityGraph for 3 levels?

*爱你&永不变心* 提交于 2019-12-06 20:19:04

问题


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.

  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.




回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!