【问题标题】:Using the Criteria API and Metamodel API to Join two Middle table always cross join使用 Criteria API 和 Metamodel API 连接两个中间表总是交叉连接
【发布时间】:2016-08-12 02:48:42
【问题描述】:

这是一个RBAC模块,有三个基本表user、role和permission以及中间映射表user_role和role_permission。

@Entity
@Table(name = "USER") 
public class User implements Serializable {
  @Id
  private String userId;
  ...
}

@Entity
@Table(name = "ROLE") 
public class Role implements Serializable {
  @Id
  private String roleId;
  ...
}

@Entity
@Table(name = "PERMISSION") 
public class Permission implements Serializable {
  @Id
  private String permissionId;
  ...
}

@Entity
@Table(name = "USER_ROLE") 
public class UserRole implements Serializable {
  @Id
  @GenericGenerator(name = "uuidGenerator", strategy = "uuid")
  @GeneratedValue(generator = "uuidGenerator")
  @Column(name = "ID")
  private String id;

  @ManyToOne
  @JoinColumn(name = "USERID")
  private User user;

  @ManyToOne
  @JoinColumn(name = "ROLEID")
  private Role role;
  ...
}

@Entity
@Table(name = "ROLE_PERMISSION") 
public class RolePermission implements Serializable {
  @Id
  private String id;

  @ManyToOne
  @JoinColumn(name = "PERMISSIONID")
  private Permission permission;

  @ManyToOne
  @JoinColumn(name = "ROLEID")
  private Role role;
  ...
}

现在我想通过 user.id 查找所有权限,SQL 表示如下:

 select rp.* from Role_Permission rp,User_Role ur where ur.roleId = rp.roleId and ur.userId = :id

但通过 Criteria API:

public Predicate toPredicate(Root<RolePermission> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
            List<Predicate> predicates = new ArrayList<Predicate>();
            if (StringUtil.isNotEmpty(userId)) {
                final Root<UserRole> userRoleRoot = criteriaQuery.from(UserRole.class);
                Join<RolePermission,UserRole> join = root.join("role", JoinType.INNER);
                Predicate predicate = criteriaBuilder.equal(join.get("roleId"), root.get("role").get("roleId"));
                predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(userRoleRoot.<UserRole>get("user").get("id"), userId));
                predicates.add(predicate);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
        }

查询构建结果为:

select count(rolepermis0_.id) as col_0_0_ from role_permission rolepermis0_ inner join role role2_ on rolepermis0_.roleid=role2_.roleid cross join user_role userrole1_ where role2_.roleid=rolepermis0_.roleid and userrole1_.userid=?

但是为什么在这里role_permission 交叉加入user_role,role_permission 如何通过条件API 加入user_role 呢?

非常感谢。

【问题讨论】:

  • 首先,您的 JPQL 无效。你在一个关系上做一个 JOIN,而不是一个类。所以从“select rp from RolePermission rp inner join rp.role r”开始。使用它来决定使用什么标准
  • JPQL 只是一个假代码。我真的只需要找到 RolePermission,SQL 表达如下:select rp.* from RolePermission rp,UserRole ur where ur.roleId = rp.roleId and ur.userId = :id
  • 首先如果它是“假代码”然后不要发布它。其次,如果你想添加一个谓词(“criteriaBuilder.equal”),你应该使用“join”而不是“root.get().get()”。此外,如果您只有 RolePermission 中的关系,那么这需要成为您在 Criteria 中的“候选人”......是吗???
  • 应该使用“加入”吗?你的意思是“谓词谓词 = criteriaBuilder.equal(join.get("roleId"), join);" ?
  • 再次查看您的模型,然后您现在发布的 SQL ......您的 SQL 意味着 CROSS JOIN。此外,您无法在 JPA 中指定 INNER JOIN,因为 UserRole 和 RolePermission 之间没有关系(因为 JPQL 和 Criteria 从关系工作),所以这些类之间的连接也只能是 CROSS JOIN

标签: jpa criteria-api


【解决方案1】:
 final Subquery<UserRole> userRoleSubquery = criteriaQuery.subquery(UserRole.class);
 final Root<UserRole> userRole = userRoleSubquery.from(UserRole.class);
 userRoleSubquery.select(userRole.<UserRole>get("id"));
 userRoleSubquery.where(criteriaBuilder.equal(root.get("role").get("roleId"), userRole.get("role").get("roleId")), criteriaBuilder.equal(userRole.get("user").get("id"), userId));
 Predicate predicate = criteriaBuilder.exists(userRoleSubquery);
 predicates.add(predicate);

【讨论】:

    猜你喜欢
    • 2015-03-23
    • 2011-08-30
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    相关资源
    最近更新 更多