如何使用JPA Criteria Builder编写查询(包括子查询并存在)

Jav*_* SE 4 hibernate jpa criteria jpa-2.0

努力使用JPA编写以下查询。

Oracle查询:

Select * from table1 s
where exists (Select 1 from table2 p
              INNER JOIN table3 a ON a.table2_id = p.id
              WHERE a.id = s.table3_id
              AND p.name = 'Test');
Run Code Online (Sandbox Code Playgroud)

另外,您想指出任何好的教程来用JPA编写复杂的查询。

luk*_*paw 6

我将使用JpaRepository,JpaSpecificationExecutor,CriteriaQuery,CriteriaBuilder回答简单汽车广告领域(广告,品牌,模型)的示例

  • 品牌[一对多]模型
  • 模型[一对多]广告

实体:

@Entity
public class Brand {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String name;
  @OneToMany(mappedBy = "brand", fetch = FetchType.EAGER)
  private List<Model> models;
}

@Entity
public class Model {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String name;
  @ManyToOne
  @JoinColumn(name = "brand_id")
  private Brand brand;
}

@Entity
public class Advert {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  @ManyToOne
  @JoinColumn(name = "model_id")
  private Model model;
  private int year;
  private int price;
}
Run Code Online (Sandbox Code Playgroud)

仓库:

public interface AdvertRepository
  extends JpaRepository<Advert, Long>, JpaSpecificationExecutor<Advert> {
}
Run Code Online (Sandbox Code Playgroud)

规格:

public class AdvertSpecification implements Specification<Advert> {
  private Long brandId;

  public AdvertSpecification(Long brandId) {
    this.brandId = brandId;
  }

  @Override
  public Predicate toPredicate(Root<Advert> root,
                               CriteriaQuery<?> query,
                               CriteriaBuilder builder) {

    Subquery<Model> subQuery = query.subquery(Model.class);
    Root<Model> subRoot = subQuery.from(Model.class);

    Predicate modelPredicate = builder.equal(root.get("model"), subRoot.get("id"));

    Brand brand = new Brand();
    brand.setId(brandId);
    Predicate brandPredicate = builder.equal(subRoot.get("brand"), brand);

    subQuery.select(subRoot).where(modelPredicate, brandPredicate);
    return builder.exists(subQuery);
  }
}
Run Code Online (Sandbox Code Playgroud)

效果就是这个Hibernate SQL:

select advert0_.id as id1_0_,
       advert0_.model_id as model_id5_0_,
       advert0_.price as price3_0_,
       advert0_.year as year4_0_
from advert advert0_
where exists (select model1_.id from model model1_
              where advert0_.model_id=model1_.id
              and model1_.brand_id=?)
Run Code Online (Sandbox Code Playgroud)


Xtr*_*ica 3

您可以使用 JPA 查询或 HQL 而不是条件构建器来更简单地完成此操作:

SELECT e1 from Entity1 as e1 
where exists
(select e2 from Entity2 as e2 join e2.e3 as ent3
where ent3.id=e1.id and e2.name='Test')
Run Code Online (Sandbox Code Playgroud)

  • Criteria builder 有其自身的局限性,因此最好根据情况将其与查询结合起来。不要试图用螺丝刀钉钉子,它会把容易变成困难。 (2认同)