【问题标题】:Hibernate Criteria query: getting a list of objects with a m..n relationship where child table does not have a certain propertyHibernate Criteria查询:获取具有m..n关系的对象列表,其中子表没有特定属性
【发布时间】:2011-05-10 09:32:49
【问题描述】:

我有以下表格

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 对象包含其他附加条件时,该解决方案也应该有效。

这是怎么做到的,或者是吗?

【问题讨论】:

    标签: java sql hibernate


    【解决方案1】:

    您需要一个子查询 (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();
    

    应该这样做。

    【讨论】:

    • 如果只有一个标准,这是一个很好的解决方案。但是,如果 Criteria 对象中有其他条件,则整个列表将被颠倒(这就是为什么我提到“如果可能的话,这应该可以通过修改 Criterion 对象来实现”)。编辑原始帖子以澄清。
    • 对不起,我不明白这个问题。您仍然可以对条件本身添加任何限制。条件本身并没有改变,它只是在子查询中使用而不是条件。
    • 如果您向标准添加另一个限制(除了角色标准),例如公司名称是“blaa”,然后是您的子标准,您将结果反转,即您得到所有​​没有角色“ADMIN”且名称不是“blaa”的公司。期望的结果是让所有没有角色“ADMIN”且具有名称“blaa”的公司。这是子查询无法做到的——如果我错了,请纠正我。
    • 是的,您需要在条件而不是子查询上添加限制 (name='blaa')。
    猜你喜欢
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2013-02-13
    • 1970-01-01
    • 2014-02-11
    • 2022-06-11
    • 2019-04-07
    相关资源
    最近更新 更多