JoinTable上的JPA Criteria Subquery

Rya*_*yan 5 jpa criteria-api

如何创建有效的JPA Criteria查询以仅在连接表中存在实体列表时才选择实体列表?例如,请使用以下三个表:

create table user (user_id int, lastname varchar(64));
create table workgroup (workgroup_id int, name varchar(64));
create table user_workgroup (user_id int, workgroup_id int); -- Join Table
Run Code Online (Sandbox Code Playgroud)

有问题的查询(我想要JPA生成的)是:

select * from user where user_id in (select user_id from user_workgroup where workgroup_id = ?);
Run Code Online (Sandbox Code Playgroud)

以下Criteria查询将产生类似的结果,但有两个连接:

    CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
    CriteriaQuery<User> cq = cb.createQuery(User.class);
    Root<User> root = cq.from(User.class);
    cq.select(root);

    Subquery<Long> subquery = cq.subquery(Long.class);
    Root<User> subroot = subquery.from(User.class);
    subquery.select(subroot.<Long>get("userId"));
    Join<User, Workgroup> workgroupList = subroot.join("workgroupList");
    subquery.where(cb.equal(workgroupList.get("workgroupId"), ?));
    cq.where(cb.in(root.get("userId")).value(subquery));

    getEntityManager().createQuery(cq).getResultList();
Run Code Online (Sandbox Code Playgroud)

基本问题似乎是我正在为USER_WORKGROUP连接表使用@JoinTable注释而不是为连接表使用单独的@Entity,所以我似乎不能在条件查询中使用USER_WORKGROUP作为Root.

这是实体类:

@Entity
public class User {
  @Id
  @Column(name = "USER_ID")
  private Long userId;
  @Column(name = "LASTNAME")
  private String lastname;
  @ManyToMany(mappedBy = "userList")
  private List<Workgroup> workgroupList;
}

@Entity
public class Workgroup {
  @Id
  @Column(name = "WORKGROUP_ID")
  private Long workgroupId;
  @Column(name = "NAME")
  private String name;
  @JoinTable(name = "USER_WORKGROUP", joinColumns = {
        @JoinColumn(name = "WORKGROUP_ID", referencedColumnName = "WORKGROUP_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID", nullable = false)})
  @ManyToMany
  private List<User> userList;
}
Run Code Online (Sandbox Code Playgroud)

Jef*_*ang 2

据我所知,JPA本质上忽略了连接表。您所做的 JPQL 是

select distinct u from user u join u.workgroupList wg where wg.name = :wgName
Run Code Online (Sandbox Code Playgroud)

对于 Criteria 查询,您应该能够执行以下操作:

Criteria c = session.createCriteria(User.class, "u");
c.createAlias("u.workgroupList", "wg");
c.add(Restrictions.eq("wg.name", groupName));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Run Code Online (Sandbox Code Playgroud)

无需担心中间连接表。