简体   繁体   English

hibernate join 获取一对多表

[英]hibernate join fetch one to many multiple tables

I have the following entity relationship in my data model.我的数据 model 中有以下实体关系。

ERD ERD

Entity A: one-to-many:Entity B

Entity B: one-to-many:Entity C

Entity B: one-to-many:Entity D

Hibernate Entities: Hibernate 实体:

public class EntityA {
    
    private Integer id;
    
    @OneToMany
    private List<EntityB> entityBList;
}

public class EntityB {
    
    private Integer id;

    @ManyToOne
    private EntityA entityA;
    
    @OneToMany(fetch=FetchType.LAZY)
    private List<EntityC> entityCList;

    @OneToMany(fetch=FetchType.LAZY)
    private List<EntityD> entityDList;
}

public class EntityC {
    
    private Integer id;
    
    @ManyToOne
    private EntityB entityB;
}

public class EntityD {

    private Integer id;

    @ManyToOne
    private EntityB entityB;
}

Requirement: I want to query on Entity C with join fetch of Entity B and also eagerly fetch Entity D at the same time.要求:我想查询实体 C 和实体 B 的连接获取,同时也急切地获取实体 D。 After the query is completed I expect that if I do entityC.getEntityB().getEntityDList() , it should not lead to N+1 query problem in hibernate.查询完成后,我希望如果我执行entityC.getEntityB().getEntityDList() ,它不应该导致 hibernate 中的 N+1 查询问题。

I was trying the following JPQL query:我正在尝试以下 JPQL 查询:

select ec from EntityC ec 
join fetch ec.entityB eb 
join fetch eb.entityD ed 
where ec.id = :id

This leads to duplicates in the result because of cross join with Entity D. Instead of one result, I get n results where n is the size of list of Entity D.由于与实体 D 的交叉连接,这导致结果重复。我得到 n 个结果,而不是一个结果,其中 n 是实体 D 列表的大小。

How can I avoid this?我怎样才能避免这种情况? Is there any way to fetch the Entity D without cross join in JPQL?有没有办法在 JPQL 中获取没有交叉连接的实体 D?

The first thing is to use the DISTINCT JPQL keyword on your query, eg as:首先是在查询中使用DISTINCT JPQL 关键字,例如:

TypedQuery<EntityC> query = em.createQuery("SELECT DISTINCT ec FROM EntityC ec JOIN FETCH ec.entityB eb JOIN FETCH eb.entityDList ed WHERE ec.id = :id", EntityC.class);
//                                                 ^^^^^^^^

This will eliminate the duplicates but has the side-effect of passing the DISTINCT to the SQL query as well, which is not something that you want.这将消除重复项,但也具有将DISTINCT传递给 SQL 查询的副作用,这不是您想要的。 Read details here , here and in this excellent answer.在此处此处出色答案中阅读详细信息。 Long story short - quoting Vlad Mihalcea's answer :长话短说 - 引用 Vlad Mihalcea 的回答

By passing DISTINCT to the SQL query, the EXECUTION PLAN is going to execute an extra Sort phase which adds overhead without bringing any value[...]通过将 DISTINCT 传递给 SQL 查询,执行计划将执行额外的排序阶段,这会增加开销而不带来任何价值[...]

The solution is in the linked articles and answers, but in short, if you are on Hibernate >= 5.2.2, use the hibernate.query.passDistinctThrough hint:解决方案在链接的文章和答案中,但简而言之,如果您使用的是 Hibernate >= 5.2.2,请使用hibernate.query.passDistinctThrough提示:

TypedQuery<EntityC> query = em.createQuery("SELECT DISTINCT ec FROM EntityC ec JOIN FETCH ec.entityB eb JOIN FETCH eb.entityDList ed WHERE ec.id = :id", EntityC.class);
query.setHint("hibernate.query.passDistinctThrough", false);
// -OR-
query.setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false); // import org.hibernate.jpa.QueryHints

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM