Запрос JPA Critiera со многими соединениями с использованием трех предикатов ИЛИ

Я пишу запрос с использованием JPA Criteria API, где я хочу получить все путешествия, соответствующие любому из этих предикатов:

  • Получить все путешествия (MasterTravels), которыми я владею (владелец = пользователь)
  • Получить все поездки, где я являюсь пассажиром (Пассажир, пользователь = пользователь)
  • Получить все путешествия, на которые я подал заявку (MasterTravelApplication, user = user)

Первый предикат прост. Я просто проверяю, если владелец = пользователь в MasterTravel. Для второго предиката мне нужно присоединиться к MasterTravel->MTT->Travel->Passenger, а затем проверить, если Passenger_.user = user. Для третьего предиката мне нужно присоединиться в другом направлении MasterTravel->MasterTravelApplication и проверить наличие MasterTravelApplication_.user = user. Это то, что ломает мой запрос, так как у меня есть два первых рабочих, но когда я пытаюсь добавить последний предикат, он перестает работать.

Должен ли я создать новый корень для последнего объединения или как я могу использовать объединение объединений 1 и 2 ниже?

CriteriaQuery<MasterTravel> q = cb.createQuery(MasterTravel.class);
Root<MasterTravel> root = q.from(MasterTravel.class);

// Joins 1, these works fine
Join<MasterTravel, MTT> mtts = root.join(MasterTravel_.mtt);
Join<MTT, Travel> travels = mtts.join(MTT_.travel);
Join<Travel, Passenger> passengers = travels.join(Travel_.passengers);                      

// Joins 2, this doesn't work
Join<MasterTravel, MasterTravelApplication> application = root.join(MasterTravel_.applications);

Predicate p = cb.or(
    cb.equal(passengers.get(Passenger_.user), user), 
    cb.equal(root.get(MasterTravel_.owner), user),
    cb.equal(application.get(MasterTravelApplication_.user), user));  // When I add this it stops working

q.select(root);
q.where(p);         
q.orderBy(cb.desc(root.get(MasterTravel_.createdTimestamp)));                       
q.distinct(true);

List<MasterTravel> resultList = em.createQuery(q).getResultList();

person Jonas    schedule 19.10.2011    source источник


Ответы (1)


Вы не описываете связи между объектами, но я предполагаю, что основное путешествие не обязательно имеет хотя бы одно приложение, и, поскольку вы выполняете внутреннее соединение, все основные путешествия, которые не имеют никакого приложения, не найден.

Используйте метод соединения, принимающий JoinType в качестве аргумента, и используйте JoinType.LEFT.

person JB Nizet    schedule 19.10.2011
comment
Да, прости. Я забыл упомянуть, что MasterTravelApplication отображается как @OneToMany в MasterTravel. С левыми соединениями вместо внутренних соединений все работает прекрасно, спасибо! - person Jonas; 19.10.2011
comment
@Jonas Если это решение. Можете ли вы поделиться тем, что вы сделали? - person feder; 06.09.2013