Запрос Hibernate Criteria: получение списка объектов с отношением m..n, для которого у дочерней таблицы нет определенного свойства - PullRequest
2 голосов
/ 10 мая 2011

У меня есть следующие таблицы

CREATE TABLE "COMPANIES" (
    "ID" NUMBER NOT NULL ,
    "NAME" VARCHAR2 (100) NOT NULL  UNIQUE
) 
/

CREATE TABLE "COMPANIESROLES" (
    "ID" NUMBER NOT NULL ,
    "COMPANYID" NUMBER NOT NULL ,
    "ROLENAME" VARCHAR2 (30) NOT NULL
) 
/

CREATE TABLE "ROLES" (
    "NAME" VARCHAR2 (30) NOT NULL
) 
/

Эта структура представляет количество компаний и роли, разрешенные для каждой компании.Для этих таблиц есть соответствующие объекты Hibernate:

public class Company implements Serializable {

    private Long id;
    private String name;
    private Set<Role> companyRoles;

    //(getters and setters omitted for readability)
}

public class Role implements Serializable {

        private String name;

        //(getters and setters omitted for readability)
}

Найти все компании, которые играют определенную роль, с помощью Hibernate Criteria API, не проблема:

Session session = this.sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(Company.class);
criterion = Restrictions.eq("companyRoles.name", "ADMIN");
criteria.add(criterion);
List<Company> companyList = criteria.list();

Hibernate переводитэто к запросу SQL (приблизительно)

SELECT *
FROM   companies this_
      inner join companyroles cr2_
         ON this_.id = cr2_.companyid
       inner join roles role1_
         ON cr2_.rolename = role1_.NAME
WHERE role1_.NAME = 'ADMIN'  

А теперь проблема: как я могу отменить запрос, то есть выяснить все компании, у которых нет сопоставления для роли "ADMIN"?Если я просто попытаюсь отменить критерий, установив

criterion = Restrictions.ne("companyRoles.name", "ADMIN");

(не равно, а не равно), Hibernate создаст запрос, подобный этому

SELECT *
FROM   companies this_
      inner join companyroles cr2_
         ON this_.id = cr2_.companyid
       inner join roles role1_
         ON cr2_.rolename = role1_.NAME
WHERE role1_.NAME != 'ADMIN'  

Очевидно, что это не приводит к желаемомувывод, так как список по-прежнему содержит компании, имеющие роль «ADMIN», при условии, что компании выполняют по крайней мере еще одну роль.

То, что я хочу иметь, это список компаний, которые не имеют роли «АДМИН».В качестве дополнительного ограничения это должно быть выполнимо путем простого изменения объекта Criterion, если это возможно (это происходит потому, что критерий создается автоматически как часть внутренней структуры, и там невозможно вносить более крупные изменения). Решение также должно работать, когда объект Criteria содержит другие дополнительные критерии.

Как это выполнимо, или это так?

1 Ответ

3 голосов
/ 10 мая 2011

Вам нужен подзапрос (DetachedCriteria).

DetachedCriteria sub = DetachedCriteria.forClass(Company.class);
criterion = Restrictions.eq("companyRoles.name", "ADMIN");
sub.add(criterion);
sub.setProjection(Projections.property("id"));
Criteria criteria = session.createCriteria(Company.class);
criteria.add(Property.forName("id").notIn(sub));
List<Company> companyList = criteria.list();

Что-то подобное должно сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...