如果我在SQL中查询:
select * from Profesor
inner join Estudiantes on Profesor.id = Estudiante.id
where Profesor.nombre = 'juan'
and Estudiante.nombre = 'jose'
该查询返回教授和学生。一名教授和一名学生。只是胡安教授,何塞是学生。
然后,如果我在JPA中查询:
select p from Profesor p
inner join p.estudiantes e
where p.nombre = juan
and e.nombre = jose.
JPA将让Juan教授与所有学生一起返回,而不仅仅是我想要的那个,而
profesor.estudiantes
将列出所有学生。我的类型是:
class Profesor{
private List<Estudiante> estudiantes;
}
class Estudiante{
String matricula;
}
对不起,我用西班牙语编写代码。我只是弄清楚了。
我不知道我是否很清楚我的问题,请告诉我。
最佳答案
您需要了解两件事。
首先:当您说Select p from Profesor
时,JPA仅从Profesor表中选择列,并返回一个Profesor实例,其中包含尚未加载的学生集合。第一次实际访问集合时,它会延迟加载。当加载集合时,它已经忘记了您用来加载教授的查询。它加载的是教授学生的集合。既然教授有很多学生,那么他们就成了所有人。初始查询类似于
select p.* from Profesor inner join ...
在SQL中执行它,您会看到它不会加载教授及其学生。它只加载一位教授。
第二:一个实体应该代表数据库中的数据。它不应该代表查询的结果。因此,教授实体中的学生集合始终是教授中所有学生的集合。
做您想做的事情,您有几种选择:
select p, s from Profesor inner join p.students s...
:这将返回包含找到的教授和找到的学生的数组。如果关联是双向的:
select s from Profesor p inner join p.students s ...
:这将加载学生,并引用其教授如果使用的是Hibernate,则违反了该领域的JPA规范:
select p from Profesor inner join fetch p.students...
:提取使hibernate在单个查询中加载教授及其学生。但是,由于您在学生上添加了where子句,因此只会加载与教授匹配的学生。请注意,第三种解决方案非常危险,我不建议您使用它。首先,因为它不是有效的JPQL。而且更重要的是,由于通过此类查询加载到Professor实体的代码期望Professor.getStudents()将返回教授的所有学生,而不仅是其中之一。因此,它可能显示错误的结果,或修改集合并导致数据库中的不一致。