怎么使用JPA CriteriaBuilder seltCase()使其可以有谓词作为结果?

本教程将介绍如何使用JPA CriteriaBuilder seltCase()使其可以有谓词作为结果?的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

怎么使用JPA CriteriaBuilder seltCase()使其可以有谓词作为结果? 教程 第1张

问题描述

我需要实现一个具有If...Then...Else方案的条件查询。
我发现javax.persistence.criteria.CriteriaBuilder.selectCase()适合于此目的。它返回Expression作为结果。

要运行条件查询,我需要使用接受谓词数组的where()。这是因为我有多个谓词要包含在查询中。

现在,由于selectCase()返回Expression,我无法将其与现有谓词列表集成。

Type mismatch: cannot convert from Expression<Object> to Predicate

怎么使用selectCase()使我可以将谓词作为结果?
或任何其他更好的方法来完成此操作?

示例:

为了说明这个问题,我有以下实现:"默认情况下,从印度获取所有特定年龄的用户和(来自特定国家和城市的)其他用户"

If...Then...Else方案

如果来自特定国家

if from particular city

否则

 if from "India"

//查询实现

@Override
 public List<User> findUsersByAgeCountryAndCity(int age, String country, String city) {
  CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  CriteriaQuery<User> cq = cb.createQuery(User.class);

  Root<User> user = cq.from(User.class);
  List<Predicate> predicates = new ArrayList<>();

  predicates.add(age(user, age));

  predicates.add(country(user, country, city));

  cq.where(predicates.toArray(new Predicate[0]));

  return entityManager.createQuery(cq).getResultList();
 }

 private Predicate country(Root<User> user, String country, String city) {
  CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  return cb.selectCase() //
 .when(cb.equal(user.get("address").get("country"), country),
cb.equal(user.get("address").get("city"), city))
 .otherwise(cb.equal(user.get("address").get("country"), "India")); 
 }

 private Predicate age(Root<User> entity, int age) {
  return entityManager.getCriteriaBuilder().equal(entity.get("age"), age);
 }

//User.java

public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private int id;

 private String name;
 private LocalDate creationDate;
 private LocalDate lastLoginDate;
 private boolean active;
 private int age;
 @Column(unique = true, nullable = false)
 private String email;
 private Integer status;
 @Embedded
 private Address address;
 @OneToMany
 List<Possession> possessionList;
...

//Address.java

@Embeddable
public class Address {

 private String city;
 private String country;
...

推荐答案

如果我没看错您的问题,您需要以下逻辑:

IF is_user_from_country 
 RETURN is_user_from_city
ELSE
 RETURN is_user_from_india

将其转换为查询很困难,因为SQL中的谓词没有可以返回的内在布尔值。在SQL术语中,它将如下所示:

CASE 
 WHEN user.country = :country THEN
  CASE WHEN user.city = :city THEN 1 ELSE 0 END
 WHEN user.country = 'India' THEN 1
 ELSE 0 
END

在Criteria API中(注意,我还没有测试过,可能有语法错误):

cb.selectCase() //
 .when(cb.equal(user.get("address").get("country"), country),
cb.selectCase()
.when(cb.equal(user.get("address").get("city"), city), cb.literal(true))
.otherwise(cb.literal(false))
 ))
 .when(cb.equal(user.get("address").get("country"), "India"), cb.literal(true))
 .otherwise(cb.literal(false)); 

但是,我不能完全确定Criteria API是否支持嵌套的CASE语句。如果不是,您可以尝试使逻辑更直接:

SELECT CASE
 WHEN user.country = :country AND user.city = :city THEN TRUE
 WHEN user.country = :country AND user.city <> :city THEN FALSE
 WHEN user.country = 'India' THEN TRUE
 ELSE FALSE
END

好了关于怎么使用JPA CriteriaBuilder seltCase()使其可以有谓词作为结果?的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。