我有以下表格
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”角色的公司,只要公司至少有一个其他角色。
我想要的是一个公司列表,它们没有“ADMIN”角色。作为一个额外的限制,如果可能的话,只需修改Criterion对象就可以做到这一点(这是因为标准是作为内部框架的一部分自动构建的,并且不可能在那里进行更大的更改)。 当Criteria对象包含其他附加标准时,解决方案也应该有效。
这是怎么做的,或者是吗?
答案 0 :(得分:3)
您需要一个子查询(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();
这样的事情应该这样做。