Использование JPA CriteriaBuilder для генерации запроса, где атрибут находится либо в списке, либо пуст

1

Я пытаюсь использовать JPA CriteriaBuilder для генерации запроса для объекта под названием "TestContact", который имеет соединение "многие-ко-многим" с другим объектом, называемым "SystemGroup", где атрибут для этого объединения называется "группами". Целью запроса является извлечение записей из объекта "TestContact", где атрибут "groups" находится либо в списке, либо пуст.

Код, который я использую, выглядит следующим образом

public List<TestContact> findWithCriteriaQuery(List<SystemGroup> groups) {

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<TestContact> cq = cb.createQuery(TestContact.class);
    Root<TestContact> testContact = cq.from(TestContact.class);
    cq.select(testContact);

    Path<List<SystemGroup>> groupPath = testContact.get("groups");

    // cq.where(groupPath.in(groups));
    // cq.where(cb.isEmpty(groupPath));
    cq.where(cb.or(cb.isEmpty(groupPath), groupPath.in(groups)));

    TypedQuery<TestContact> tq = em.createQuery(cq);

    return tq.getResultList();
}

Проблема заключается в том, что этот запрос возвращает результаты, когда группа находится в списке "группы", но по какой-то причине также не возвращает результаты, когда группа пуста (т.е. В таблице соединений нет записи)

Если я изменил предложение cq.where(cb.isEmpty(groupPath)); на cq.where(cb.isEmpty(groupPath)); то запрос правильно возвращает результаты, когда группа пуста.

Если я изменил предложение cq.where(groupPath.in(groups)); на cq.where(groupPath.in(groups)); то запрос правильно возвращает результаты, в которых группа находится в списке "группы".

Я не понимаю, почему, когда я пытаюсь объединить эти два предиката с помощью CriteriaBuilder или метода, результаты не включают записи, в которых группа находится либо в списке, либо пусто.

Атрибут групп в объекте "TestContact" объявляется следующим образом

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name = "TEST_CONTACT_GROUPS", joinColumns = { @JoinColumn(name = "CONTACT_ID", referencedColumnName = "CONTACT_ID") }, inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", referencedColumnName = "GROUP_ID") })
private List<SystemGroup> groups;

Поставщиком JPA является EclipseLink 2.5.0, сервер приложений Java EE - GlassFish 4, а база данных - Oracle 11gR2.

Может ли кто-нибудь указать, где я ошибаюсь?

Обновить

Я попробовал предложение от @Chris, но Eclipse возвращает следующую ошибку в Join<List<SystemGroup>> groupPath = testContact.join("groups", JoinType.LEFT)

Некорректное количество аргументов для типа Join; его нельзя параметризовать аргументами>

Глядя на JavaDoc для Join он говорит, что параметры типа...

Z - тип источника соединения, X - целевой тип соединения

Я пробовал Join<TestContact, SystemGroup> groupPath = testContact.join("groups", JoinType.LEFT); который затем заставляет Eclipse возвращать следующую ошибку на cb.isEmpty

Связанное несоответствие: общий метод isEmpty (Выражение) типа CriteriaBuilder не применим для аргументов (Join). Выведенный тип SystemGroup не является допустимым заменителем ограниченного параметра>

Теги:
jpa
criteria-api
eclipselink

1 ответ

0
Лучший ответ

TestContact.get("groups"); обязывает внутреннее соединение от testContact к группам, которое отфильтровывает testContacts без групп. Вам нужно указать левое внешнее соединение и использовать его в своих предложениях isEmpty и в.

Root<TestContact> testContact = cq.from(TestContact.class);
cq.select(testContact);

Join<TestContact, SystemGroup> groupPath = testContact.join("groups", JoinType.LEFT);
cq.where(cb.or(cb.isEmpty(testContact.get("groups")), groupPath.in(groups)));

Я обычно ссылаюсь на https://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join для примеров

  • 0
    Спасибо - я попробовал ваше предложение, но я получаю сообщение об ошибке в Join<List<SystemGroup>> groupPath = testContact.join("groups", JoinType.LEFT); , Я обновил оригинальный вопрос с некоторыми дополнительными деталями. Есть идеи?
  • 0
    У меня не было тестового проекта, чтобы попробовать его в первую очередь. Я обновил пример, который теперь должен работать - я считаю, что JPA должен использовать .get ("groups") для создания подзапроса, в то время как внешнее соединение с отношением для предложения 'in'.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню