首页 > 解决方案 > Criteria API 连接问题:不包含关系列的实体不能“连接”

问题描述

所需的实体大致如下:

@Entity
@Table(name = "tb_users")
public class User {

    @Id
    @GeneratedValue
    private UUID userId;

    // Omitted other fields and getters/setters ...
}
@Entity
@Table(name = "tb_groups")
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer groupId;

    // ....
}
@Entity
@Table(name = "tb_group_members")
public class GroupMember {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "group_id")
    private Group group;

    // getters & setters ...
}

这是与中间表的多对多关系:

组 <----- 1:N -----> GroupMember <----- N:1 -----> 用户

我想要实现的查询(通过Criteria API)与下面的JPQL基本相同:

select g from Group g join GroupMember gm on g = gm.group where gm.user = ? and  ...or whatever...

我尝试按如下方式构造 CriteriaQuery:

User userToQuery = ...;
// ....
CriteriaQuery<Group> query = criteriaBuilder.createQuery(Group.class);
Root<Group> groupRoot = query.from(Group.class);
Root<GroupMember> gmRoot = query.from(GroupMember.class);
groupRoot.join(...).on(criteriaBuilder.equal(groupRoot, gmRoot.get("group"))); // I can't find a suitable join() method to specify the relationship
Predicate predicate = criteriaBuilder.equal(gmRoot.get("user"), userToQuery);
// ......

由于Group实体没有关联关系,所以不知道怎么调用join(...)方法。

我必须反向声明关联,即从 GroupMember 实体:

CriteriaQuery<GroupMember> query = criteriaBuilder.createQuery(GroupMember.class);
Root<GroupMember> gmRoot = query.from(GroupMember.class);
gmRoot.join("group");
// ......

JPA 的 Criteria API 有这个限制吗?不包含关联字段join的实体如何与其他实体?

标签: jpaspring-data-jpacriteria-api

解决方案


基于Querydsl的实现:

private EntityManager em;

......

User user = ...; // User to query (may be null)
...
QGroup qGroup = QGroup.group;
QGroupMemeber qGMember = QGroupMember.groupMember;

JPAQueryFactory queryFactory = new JPAQueryFactory(em);
JPAQuery<Group> query = (user == null) ?
        queryFactory.selectFrom(qGroup) :
        queryFactory.select(qGroup).from(qGroup).join(qGMember).on(qGroup.eq(qGMember.group));

BooleanBuilder builder = new BooleanBuilder();
if (user != null) {
    builder.and(qGMember.user.eq(user));
}
// if (...) {
//     Other conditions that need to be added to the where clause
// }
query.where(builder);
// Paging condition or something
// ....

List<Group> result = query.fetch(); // search result

推荐阅读