spring data jpa不必要的左连接

时间:2017-05-13 04:08:25

标签: java spring postgresql jpa spring-data-jpa

我有以下型号:

enter image description here

我希望获得指定Institutions的所有sectorId(Intituciones)。

tbInstitucion模型中,我与tbSector建立了关系:

 @ManyToOne(fetch=FetchType.LAZY)
 @JoinColumn(name="`sectorId`")
 private Sector sector;

有没有办法获得如下的查询:

select * 
from tbInstitucion 
where sectorId = ?

我尝试过:findBySector(Sector sector)

但是有了这个,我需要一个额外的查询来查找扇区,findBySector正在生成以下查询:

select
        generatedAlias0.institucionId,
        generatedAlias0.institucionNombre 
    from
        Institucion as generatedAlias0 
    left join
        generatedAlias0.sector as generatedAlias1 
    where
        generatedAlias1=:param0

尝试了另外一个:

findBySector_sectorId

也会生成上述查询。

形成如下的查询不会更好:

select * 
from tbInstitucion 
where sectorId = ?

有没有办法获得上述查询? 为什么JPA会产生左连接?

2 个答案:

答案 0 :(得分:5)

  

快速回顾实体模型

@Entity
class Institucion {
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="`sectorId`")
  private Sector sector;
}

相当于:

@Entity
class Institucion {
  @ManyToOne(cascade = {}
             , fetch=FetchType.LAZY
             , optional = true
             , targetEntity = void.class)
  @JoinColumn(columnDefinition = ""
             , foreignKey = @ForeignKey
             , insertable = true
             , name="`sectorId`"
             , nullable = true
             , referencedColumnName = ""
             , table = ""
             , unique = false
             , updatable = false)
  private Sector sector;
}

注意@ManyToOne(optional = true)@JoinColumn(nullable = true)。这向ORM表明sector的{​​{1}}属性是可选的,并且可能不会一直设置(到非空值)。

  

实体模型如何影响存储库查询

现在考虑以下存储库:

Institucion

鉴于上面的实体声明,存储库方法应该产生诸如以下的查询:

public interface InstitucionRepository extends CrudRepository<Institucion, Long> {
  List<Institucion> findAllByInstitucionNombre(String nombre);

  List<Institucion> findAllByInstitucionEmail(String email);
}

select
    generatedAlias0 
from
    Institucion as generatedAlias0 
left join
    generatedAlias0.sector as generatedAlias1 
where
    generatedAlias0.institucionNombre=:param0

这是因为实体模型指示select generatedAlias0 from Institucion as generatedAlias0 left join generatedAlias0.sector as generatedAlias1 where generatedAlias0.institucionEmail=:param0 是可选的,因此ORM需要加载sector而不必担心他们的Institucion

遵循此模式,以下存储库方法:

sector

转换为:

  List<Institucion> findAllBySector(Sector sector);
  

解决方案1 ​​

如果select generatedAlias0 from Institucion as generatedAlias0 left join generatedAlias0.sector as generatedAlias1 where generatedAlias1=:param0 不是可选的,请在模型中强制使用它:

Institucion.sector
  

解决方案2

如果 @ManyToOne(fetch=FetchType.LAZY, optional = false) @JoinColumn(name="`sectorId`", nullable = false) private Sector sector; 确实是可选的,那么只有@ MaciejKowalski答案中显示的手动查询才有效。

  

简化查询

以下查询也可以使用:

Institucion.sector

这假设模型属性名称完全如帖子所示。

答案 1 :(得分:1)

左连接是默认的隐式连接策略,在使用@EntityGraph功能时也是如此。

我建议使用明确的@Query定义:

@Query("select i from institution i inner join i.sector s where s.id = :sectorId")
public Institution getBySector(@Param("sectorId") Integer sectorId);