I have the following model:
I want to get all Institutions
(Intituciones) with specified sectorId
.
In the tbInstitucion
model I have a relationship with tbSector
:
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="`sectorId`")
private Sector sector;
is there a way to obtain a query like:
select *
from tbInstitucion
where sectorId = ?
I tried with: findBySector(Sector sector)
but with this I need an additional query to find the sector and findBySector
is generating the following query:
select
generatedAlias0.institucionId,
generatedAlias0.institucionNombre
from
Institucion as generatedAlias0
left join
generatedAlias0.sector as generatedAlias1
where
generatedAlias1=:param0
tried with this other one:
findBySector_sectorId
which generates the above query as well.
Wouldn't be better to form a query like:
select *
from tbInstitucion
where sectorId = ?
Is there a way to get the above query? Why is JPA generating the left join?
A quick review of the entity model
@Entity
class Institucion {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="`sectorId`")
private Sector sector;
}
is equivalent to:
@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;
}
Note @ManyToOne(optional = true)
and @JoinColumn(nullable = true)
. This signifies to the ORM that the sector
attribute of Institucion
is optional and may not be set (to a non-null value) all the time.
How the entity model impacts repository queries
Now consider the following repository:
public interface InstitucionRepository extends CrudRepository<Institucion, Long> {
List<Institucion> findAllByInstitucionNombre(String nombre);
List<Institucion> findAllByInstitucionEmail(String email);
}
Given the entity declaration above, the repository methods should produce queries such as:
select
generatedAlias0
from
Institucion as generatedAlias0
left join
generatedAlias0.sector as generatedAlias1
where
generatedAlias0.institucionNombre=:param0
and
select
generatedAlias0
from
Institucion as generatedAlias0
left join
generatedAlias0.sector as generatedAlias1
where
generatedAlias0.institucionEmail=:param0
This is because the entity model indicates sector
to be optional so the ORM needs to load Institucion
s without worrying about their sector
s.
Following this pattern, the following repository method:
List<Institucion> findAllBySector(Sector sector);
translates to:
select
generatedAlias0
from
Institucion as generatedAlias0
left join
generatedAlias0.sector as generatedAlias1
where
generatedAlias1=:param0
Solution 1
If Institucion.sector
is not optional, make it mandatory in the model too:
@ManyToOne(fetch=FetchType.LAZY, optional = false)
@JoinColumn(name="`sectorId`", nullable = false)
private Sector sector;
Solution 2
If Institucion.sector
is indeed optional, only a manual query such as the one shown in @MaciejKowalski's answer will work.
Simplified query
The following query will also work:
List<Institucion> findAllBySectorSectorId(Long id);
This assumes that the model attribute names are exactly as shown in the post.
Left join is a default implicit joining strategy, also when using the @EntityGraph
feature.
I would recommend using explicit @Query
definition:
@Query("select i from institution i inner join i.sector s where s.id = :sectorId")
public Institution getBySector(@Param("sectorId") Integer sectorId);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With