Как мне сказать в JPA, дайте мне все объекты, поле коллекции которых имеет хотя бы один элемент в другом списке?

У меня есть объект JPA со следующим полем:

@ManyToMany
@JoinTable(name = "user_organization", 
           joinColumns = { @JoinColumn(name = "USER_ID") },  
           inverseJoinColumns = { @JoinColumn(name = "ORGANIZATION_ID") })
@LazyCollection(LazyCollectionOption.FALSE)
@SortNatural
private SortedSet<Organization> organizations = new TreeSet<Organization>();

Имея список объектов Organization (myOrgs) и используя CriteriaBuilder, как мне написать предложение, чтобы сказать:

Дайте мне все User объекты, у которых есть хотя бы один Organization в переменной myOrgs?

Я пробовал следующее, но безуспешно...

final CriteriaBuilder builder = m_entityManager.getCriteriaBuilder();
final CriteriaQuery<User> criteria = builder.createQuery(User.class);
final Root<User> userRoot = criteria.from(User.class);
criteria.where(builder.isMember(myOrgs, userRoot.get(User_.organizations)), ...

Я использую JPA 2.1 с Hibernate 4.3.6.Final.


person Dave    schedule 17.11.2015    source источник
comment
Полезный URL? stackoverflow.com/ вопросы/6340554/   -  person Darryl Miles    schedule 17.11.2015
comment
Вы пробовали сначала с SQL/JPQL? Тогда перевод в критерии был бы намного проще.   -  person wypieprz    schedule 09.12.2015


Ответы (1)


Доброе утро, я бы попробовал следующее:

//GET A LIST OF IDS
List<Long> orgsIds = new ArrayList<>();
for (Organization org : myOrgs){
    orgsIds.add(org.getId());
}

//CREATE QUERY WITH JOIN AND NOT FINAL
CriteriaBuilder builder = m_entityManager.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> userRoot = criteria.from(User.class);
Join<User,Organization> organizationJoin = userRoot.join(User_.organizations,JoinType.INNER)

//DISTINCT BECAUSE JOIN WITH MULTIPLE ORGs RETURN REPEATED RESULTS
criteria.select(cb.distinct(userRoot));

criteria.where(organizationJoin.get(Organization_.id).in(orgsIds));

Другой вариант, новый в JPA 2.1 и более эффективный, заключается в том, что в соединении добавляется еще одно условие, подобное этому:

Join<User,Organization> organizationJoin = userRoot.join(User_.organizations,JoinType.INNER);
organizationJoin.on(cb.and(organizationJoin.get(Organization_.id).in(orgsIds)));

и удаление пункта where

person JLazar0    schedule 04.07.2019