【问题标题】:Querying many to many association where the entity doesn't have a certain value using Hibernate Criteria API使用 Hibernate Criteria API 查询实体没有特定值的多对多关联
【发布时间】:2011-08-29 19:56:06
【问题描述】:

我有两个类用户和角色,它们使用多对多关联相互映射。现在我正在尝试使用 Hibernate Criteria API 查询所有没有特定角色的用户。但我有点卡住了。

要查询具有特定角色的用户,我使用以下查询,效果很好。

Session session = getSessionFactory().getCurrentSession();          
Criteria mainCrit = session.createCriteria(boClass);
return mainCrit.createAlias("roles", "r").add( Restrictions.eq("r.name", roleName)).list();

现在我有点困惑如何反转查询并获取所有没有特定角色的用户。如果可能的话,我想明确排除某个角色,并且不要查询使用 OR 链接它们的所有角色,因为以后可能会动态添加更多角色。

更新

为了更好地理解我的场景,您可以在 another question 中查看我尝试查询的关联。

另外我还要补充一点,Role类的name属性是一个Enum,不知道是不是很重要或者改变了查询数据库的方式。

【问题讨论】:

    标签: java hibernate many-to-many criteria-api


    【解决方案1】:

    也许有一种更优雅的方法,但我发现的唯一一种方法是查询在具有给定角色名称的用户角色中不存在任何角色的所有用户。

    这样做是这样的:

    Criteria c = session.createCriteria(User.class, "user");
    
    DetachedCriteria roleOfUserWithName = DetachedCriteria.forClass(Role.class, "role");
    roleOfUserWithName.createAlias("role.users", "userOfTheRole");
    roleOfUserWithName.add(Restrictions.eqProperty("userOfTheRole.id", "user.id"));
    roleOfUserWithName.add(Restrictions.eq("role.name", roleName);
    roleOfUserWithName.setProjection(Projections.id());
    
    c.add(Subqueries.notExists(roleOfUserWithName));
    

    相当于下面的HQL查询:

    select user from User user where not exists (
        select role.id from Role role inner join role.users userOfTheRole
        where userOfTheRole.id = user.id
        and role.name = :roleName);
    

    【讨论】:

    • 不幸的是它对我不起作用。既不是标准也不是 HQL 版本。我正在尝试查询关联表单this question。问题是在我改变了我的协会之后,就像你在回答那个问题时建议的那样。我在这个问题中提到的查询具有特定角色的用户的查询不再起作用。不,我完全搞不懂我做错了什么。
    • 更明确。 “不起作用”是什么意思?它会产生错误吗?生成的 SQL 是否正确?它返回什么?
    • 不,它不会产生错误。首先更改行'roleName.setProjection(Projections.id());'到 'roleOfUserWithName.setProjection(Projections.id());'。我的测试场景:我创建了 3 个用户和 2 个角色(管理员、用户)。第一个用户获得管理员角色,第二个用户获得两个角色,最后一个用户获得用户角色。然后我将用户添加到关联(角色)的另一端并保存所有对象。因此,对于这种情况,查询应该返回没有管理员角色的用户。所以在这种情况下,应该只返回最后一个具有用户角色的用户。但是查询返回的列表是空的。
    • 确保在单独的测试中运行查询(在数据库中预先准备好数据),或者至少在执行查询之前刷新会话。但是,通过在同一测试中创建实体和测试查询,您会使事情变得更加复杂,因为错误可能来自查询和插入。
    • 太好了,刷新会话成功了!!非常感谢。我想我还是不明白hibernate是如何在后台工作的,你有什么好的教程建议吗?
    猜你喜欢
    • 2010-10-17
    • 2010-09-20
    • 2013-11-15
    • 2020-07-04
    • 2010-12-18
    • 2021-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多