【问题标题】:JPA Criteria JOIN et ONJPA 标准 JOIN et ON
【发布时间】:2014-04-02 13:36:38
【问题描述】:

我已经搜索了一段时间,我没有找到任何对我的问题的回应。

我正在 JSF、EclipseLink、Glassfish 中制作一个应用程序,其中用户可以拥有一个或多个组。该应用程序包含以下模块和权限:

  • 模块 => 权限 => utilisateur
  • 模块 => 权限 => groupe => utilisateur

我正在寻找一个标准查询(不在 jqpl 中)来获取用户的所有模块。我已经构建了我的 SQL 查询,它的功能非常好,如下所示:

SELECT *
FROM core_module m
WHERE m.id IN (
    SELECT m.id
    FROM core_module m
    INNER JOIN modules_permissions mp
        ON mp.modules_id = m.id
    INNER JOIN core_permission p
        ON p.id = mp.permissions_id
    INNER JOIN users_permissions up
        ON p.id = up.permissions_id
    INNER JOIN core_user u
        ON u.id = 1
)
OR m.id IN (
    SELECT m.id
    FROM core_module m
    INNER JOIN modules_permissions mp
        ON m.id = mp.modules_id
    INNER JOIN core_permission p
        ON p.id = mp.permissions_id
    INNER JOIN groups_permissions gp
        ON gp.permissions_id = p.id
    INNER JOIN core_group g
        ON g.id = gp.groups_id
    INNER JOIN users_groups ug
        ON g.id = ug.groups_id
    INNER JOIN core_user u
        ON u.id = ug.users_id
    WHERE u.id = 1
)

我正在尝试以某种方式将其转换为条件查询,但没有取得很大成功。我刚刚开始了查询的第一部分,它为我提供了用户可以立即访问的模块。我的印象是我缺少一些条件或连接,因为我得到了 2 个结果,而我不应该得到任何结果。实际上,我无法包含我的 ON 子句,因此我无法在查询中更改我的 to 连接,因为实体不存在:表 modules_permissions@ManyToMany 创建我的实体...

这是我的第一个子查询草稿:

List<Module> modules;
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Module> query = cb.createQuery(Module.class);

Root<Module> root_module = query.from(Module.class);
Root<User> root_user = query.from(User.class);
Root<Permission> root_permission = query.from(Permission.class);
Root<Group> root_group = query.from(Group.class);

Join<Module, Permission> join_module_permission = root_module.join(Module_.permissions);
Join<Permission, User> join_permission_user = root_permission.join(Permission_.users);
query.where(cb.equal(root_user.get(User_.email), current.getEmail()));
modules = getEntityManager().createQuery(query).getResultList();

【问题讨论】:

  • 嗨 Archi,这是一个英语论坛。我试图翻译你的问题。以后,请用英文发布您的问题和答案。
  • 非常感谢翻译!

标签: jpa glassfish eclipselink criteria builder


【解决方案1】:

尝试将 EclipseLink 日志记录设置为最好,以便您可以see 生成的 SQL。您也可以使用 JPQL,因为它更接近 SQL,然后在您有工作时转换为标准。像

"select m from Module m where 
    m in (select m1 from Module m1 join m1.permissions p join p.users u where u.id = 1) or
    m in (select m2 from Module m2 join m2.permissions p2 join p2.groups g join g.users u2 where u2.id =1)"

这里的关键是您在条件查询中使用实体关系,以便它匹配您在生成的 SQL 中想要的内容。当您只想将这些表及其连接包含在内部查询中时,不要使用多个 from 子句。如果上述 JPQL 有效并且存在关系,则类似这样的内容是等价的:

CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Module> query = cb.createQuery(Module.class);

Root<Module> root_module = query.from(Module.class);
Path path = root_module.get(Module_.id);

Subquery<Integer> subquery = criteriaQuery.subquery(Integer.class);
Root subRoot = subquery.from(Module.class);
subquery.select(subRoot.get((Module_.id)));
Join user1 = subRoot.join(Module_.permissions).join(Permission_.users);
subquery.where(criteriaBuilder.equals(user1.get(User_.id), 1));

Subquery<Integer> subquery2 = criteriaQuery.subquery(Integer.class);
Root subRoot2 = subquery.from(Module.class);
subquery2.select(subRoot2.get((Module_.id)));
Join user2 = subRoot2.join(Module_.permissions).join(Permission_.groups).join(Group_.users);
subquery2.where(criteriaBuilder.equals(user2.get(User_.id), 1));

query.where(criteriaBuilder.or(criteriaBuilder.in(path ).value(subquery),
                                criteriaBuilder.in(path ).value(subquery2)));

【讨论】:

  • Criteria builder 有问题 => ejb 异常
  • 非法使用 getField() [core_module.ID] un 表达式
  • 生成的 SQL 是什么?它与从 JPQL 创建的 SQL 有何不同?
  • 未生成 SQL。直接 EJB 异常。
  • 尽可能简化查询,然后一一添加回子句,直到找出导致错误的原因。您还应该发布完整的异常堆栈跟踪,并尝试最新的 Eclipselink 版本 (2.5.1)
【解决方案2】:

最终答案是:

  • 在 JPQL 中:

    @NamedQuery(name = "core_user.findModuleAssociated", query = "select m from Module m where m.id in (select m1.id from Module m1 join m1.permissions p join p.user u where u.id = :userid) or m.id in (select m2.id from Module m2 join m2.permissions p2 join p2.group g join g.users u2 where u2.id = :userid)")    
    
  • 在条件查询中:

    List<Module> modules;
    CriteriaQuery<Module> query = cb.createQuery(Module.class);
    
    Root<Module> root_module = query.from(Module.class);
    Path path = root_module.get(Module_.id);
    
    Subquery<Integer> subquery = query.subquery(Integer.class);
    Root subRoot = subquery.from(Module.class);
    subquery.select(subRoot.get((Module_.id)));
    Join user1 = subRoot.join(Module_.permissions).join(Permission_.user);
    subquery.where(cb.equal(user1.get(User_.id), current.getId()));
    
    Subquery<Integer> subquery2 = query.subquery(Integer.class);
    Root subRoot2 = subquery.from(Module.class);
    subquery2.select(subRoot2.get((Module_.id)));
    Join user2 = subRoot2.join(Module_.permissions).join(Permission_.group).join(Group_.users);
    subquery2.where(cb.equal(user2.get(User_.id), current.getId()));
    
    query.where(cb.or(cb.in(path).value(subquery), cb.in(path).value(subquery2)));
    modules = getEntityManager().createQuery(query).getResultList();
    

特别感谢克里斯

【讨论】:

    猜你喜欢
    • 2015-07-31
    • 2018-11-06
    • 2020-06-25
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 2015-02-23
    • 2021-12-19
    • 1970-01-01
    相关资源
    最近更新 更多