如果我在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()将返回教授的所有学生,而不仅是其中之一。因此,它可能显示错误的结果,或修改集合并导致数据库中的不一致。

09-28 07:45