Criteria API规范JPA加入

问题描述

这是我目前的模特

@Entity
public class A {

@Id
private Long id;

String name;

...

@Entity
public class B {

@Id
private Long id;

@ManyToOne()
@JoinColumn(name = "a_id")
private A a;

@ManyToOne()
@JoinColumn(name = "c_id")
private C c;

...

@Entity
public class C {

@Id
private Long id;

private String status;

我想要一个类别A的列表,其中类别C的状态为“活动” 使用带有显式JOIN的Criteria API 作为下面的示例,并使用 IN

Subquery<B> subQB = query.subquery(B.class);
Root<B> rootB = subQB.from(B.class);
subQB.select(rootB.get("c").get("id"))
                      .where(builder.equal(rootB.get("c").get("status"),"ACTIVE"));        
predicates.add(root.get("id").in(subQB)); // root is class A

感谢您的帮助。

解决方法

没有一个实际运行的数据库,它是否应该类似于

CriteriaBuilder cb = em.getCriteriaBuilder();

// Because the result is "A"
CriteriaQuery<A> q = cb.createQuery(A.class);

// Start from B
Root<B> bRoot = q.from(B.class);

// Path from B to A,as local variable to increase readability
Path<A> aPath = bRoot.get("a");

// Path from B to C and to C's status,as local variable to increase readability
Path<C> cPath = bRoot.get("c");
Path<String> cStatusPath = cPath.get("status");

// SELECT A FROM B WHERE B.C.Status = "ACTIVE"
q.select(aPath)
  .where(cb.equal(cStatusPath,"ACTIVE"));

编辑:

显式联接应该看起来与第一种解决方案非常相似,所以

CriteriaBuilder cb = em.getCriteriaBuilder();

// Because the result is "A"
CriteriaQuery<A> q = cb.createQuery(A.class);

// Start from B
Root<B> bRoot = q.from(B.class);

// Path from B to A,as local variable to increase readability
Path<A> aPath = bRoot.get("a");

// Join from B to C and to C's status,as local variable to increase readability
Join<B,C> cJoin = bRoot.join("c");
Path<String> cStatusPath = cJoin.get("status");

// SELECT A FROM B WHERE B.C.Status = "ACTIVE"
q.select(aPath)
  .where(cb.equal(cStatusPath,"ACTIVE"));