Почему JPA join возвращает слишком много результатов? - PullRequest
1 голос
/ 15 марта 2012

Если я запрашиваю в 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 вернет профессору Хуану всех студентов, а не только того, кого я хотел, и profesor.estudiantes получит список с всеми студентами.

Мои типы:

class Profesor{
    private List<Estudiante> estudiantes;
}

class Estudiante{
    String matricula;
}

Извините, я пишу по-испански. Я просто выяснил это.

Я не знаю, был ли я ясен в моем вопросе, пожалуйста, скажите мне.

1 Ответ

2 голосов
/ 15 марта 2012

Вам нужно понять две вещи.

Во-первых: когда вы говорите Select p from Profesor, JPA выбирает только столбцы из таблицы Profesor и возвращает экземпляр Profesor, содержащий коллекцию студентов, которая еще не загружена. Он загружается лениво, когда вы впервые получаете доступ к коллекции. И когда он загружает коллекцию, он забывает, какой запрос вы использовали для загрузки профессора. То, что он загружает, является коллекцией студентов профессора. А поскольку у профессора много студентов, это все равно. Начальный запрос похож на

select p.* from Profesor inner join ...

Выполните его в SQL, и вы увидите, что он не загружает профессора и его ученика. Он загружает только профессора.

Второе: объект должен представлять данные в базе данных. Он не должен представлять результат запроса. Таким образом, собрание студентов в лице профессора - это всегда собрание всех студентов профессора.

Чтобы сделать то, что вы хотите, у вас есть несколько вариантов:

  1. select p, s from Profesor inner join p.students s...: это вернет массив, содержащий найденного профессора и найденного ученика.
  2. если ассоциация двунаправленная: select s from Profesor p inner join p.students s ...: это загрузит студента и отсылает его к профессору
  3. при использовании Hibernate, который нарушает спецификацию JPA в этой области: select p from Profesor inner join fetch p.students...: выборка заставляет hibernate загружать профессора и его учеников в одном запросе. Но поскольку вы добавили предложение where для студента, он загружает только подходящих студентов профессора.

Обратите внимание, что третье решение очень опасно, и я бы не советовал его использовать. Во-первых, потому что это не действительно JPQL. И что еще более важно, потому что код, загружающий сущность Professor, загруженную таким запросом, ожидает, что Professor.getStudents () вернет всех студентов профессора, а не только одного из них. Таким образом, он может отображать ложные результаты или изменять коллекцию и вызывать несогласованность в базе данных.

...