Java Spring JPA优化可传递@manytone抓取

Java Spring JPA优化可传递@manytone抓取,java,mysql,spring,hibernate,jpa,Java,Mysql,Spring,Hibernate,Jpa,在我的项目中,我有三个这样的实体: @Entity public class A { @Id private int id; } @Entity public class B { @Id private int id; @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false) @OnDelete(act

在我的项目中,我有三个这样的实体:

@Entity
public class A {
    @Id
    private int id;
}

@Entity
public class B {
    @Id
    private int id;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private A a;
}

@Entity
public class C {
    @Id
    private int id;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private B b;
}
正如您所看到的,
C
a
有一个正的多音关系。 现在,我想使用我的
JpaRepository
获取所有带有特定
a
C

public interface CRepository extends JpaRepository<C, Integer> {
    List<C> findAllByBA(A a);
}
公共接口证书扩展了JPA证书{
列出findAllByBA(A);
}
这将导致以下Hibernate sql查询(这很好):

休眠:选择。。。从c c0_uu交叉连接b b1_u,其中c0_u.b_uid=b1_u.id和b1_u.a_uid=

但之后,我得到了针对每个不同
B
的另一个查询(可能有几千个,所以不好):

休眠:选择。。。从b0_uu内部连接b0_u上的a1_u.a_uid=a1_u.id,其中b0_u.id=



显然,这可以通过使用所有三个表的单个联接来解决。但是我如何告诉Hibernate使用
JpaRepository
在不失去抽象便利的情况下做到这一点呢?

额外的、不需要的查询是由于关联是急切的。要避免加载Bs,应使关联变为惰性:

@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)

我通常让每个人都变得懒惰。当您对Bs不感兴趣,或者事先不知道是否需要加载Bs时,使关联延迟可以避免加载Bs。如果您知道希望将Bs与Cs一起加载,则只需在查询中显式加载它们:

@Query("select c from C c left join fetch c.b where c.b.a = ?") 

额外的、不需要的查询是由关联是急切的这一事实引起的。要避免加载Bs,应使关联变为惰性:

@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)

我通常让每个人都变得懒惰。当您对Bs不感兴趣,或者事先不知道是否需要加载Bs时,使关联延迟可以避免加载Bs。如果您知道希望将Bs与Cs一起加载,则只需在查询中显式加载它们:

@Query("select c from C c left join fetch c.b where c.b.a = ?") 

为什么不直接使用@query注释?@gtosto我以前没有使用过
@query
。它如何与
@ManyToOne
?为什么不直接使用@query annotation?@gtosto我以前没有使用过
@query
。它是如何与
@manytone
协同工作的?“我通常会让每个关联都变得懒惰。”不!这是一个非常糟糕的主意,在这里没有任何意义,因为即使关系很紧张,也可以使用join-fetch。如果将所有关联都设置为惰性,那么最终将得到大量初始化代码。另外,LAZY只适用于非可选的ToOne引用。对不起,这不是我的解决方案。我正在使用vaadin UI中的实体,我不想用hibernate会话污染UI。查询(“select c from c join fetch c.b where c.b.a=?”)应该适用于您的情况,而不需要延迟。试试看。否则,问题是您是否真的想要实体,还是最好使用DTO。也许你能多解释一下你想要达到的目标。@SimonMartinelli问题是,我知道我在做什么。因此,我不喜欢加载默认情况下不需要的东西(使事情变得急切正是导致大量无用的查询和初始化的原因),并在需要时使用join-fetch高效地加载事情。不,lazy可以很好地处理可选的toOne关联。@F43nd1r您能澄清一下“我不想用hibernate会话污染UI”是什么意思吗。为什么您认为使用连接获取加载关联并让hibernate使用EAGER加载关联会有什么不同呢?“我通常会让每个关联都变懒。”不!这是一个非常糟糕的主意,在这里没有任何意义,因为即使关系很紧张,也可以使用join-fetch。如果将所有关联都设置为惰性,那么最终将得到大量初始化代码。另外,LAZY只适用于非可选的ToOne引用。对不起,这不是我的解决方案。我正在使用vaadin UI中的实体,我不想用hibernate会话污染UI。查询(“select c from c join fetch c.b where c.b.a=?”)应该适用于您的情况,而不需要延迟。试试看。否则,问题是您是否真的想要实体,还是最好使用DTO。也许你能多解释一下你想要达到的目标。@SimonMartinelli问题是,我知道我在做什么。因此,我不喜欢加载默认情况下不需要的东西(使事情变得急切正是导致大量无用的查询和初始化的原因),并在需要时使用join-fetch高效地加载事情。不,lazy可以很好地处理可选的toOne关联。@F43nd1r您能澄清一下“我不想用hibernate会话污染UI”是什么意思吗。为什么您认为使用join-fetch加载关联和让hibernate使用EAGER加载关联会有什么不同?