JoinTable上的JPA Criteria Subquery

时间:2013-12-05 16:19:43

标签: 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

有问题的查询(我希望JPA生成的内容)是:

select * from user where user_id in (select user_id from user_workgroup where workgroup_id = ?);

以下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();

基本问题似乎是我正在为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;
}

1 个答案:

答案 0 :(得分:1)

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

select distinct u from user u join u.workgroupList wg where wg.name = :wgName

对于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);

无需担心中间联接表。