CriteriaBuilder:在运行时根据 DataType 创建 Criteria

Posted

技术标签:

【中文标题】CriteriaBuilder:在运行时根据 DataType 创建 Criteria【英文标题】:CriteriaBuilder: Create Criteria based on DataType at runtime 【发布时间】:2019-01-25 13:51:30 【问题描述】:

我有一个简化的Entity 类,如下所示:

@Entity
public class Student 
    String name;
    Date birthday;
    Integer term;

第三方依赖项(DataTables)以Map<String,String> 的形式发送搜索请求,其中key 是实体属性的名称,value 是搜索String。地图可能如下所示:

key      |   value
------------------
name     |   Alice
birthday |    2000
term     |       3

我目前使用这个实现,它适用于String 属性,如name

public List<Student> getStudents(Map<String,String> filters) throws Exception 
    //get builder
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery cq = cb.createQuery();
    Root<Student> student = cq.from(Student.class);

    //validate if attribut exists
    try 
        for(String key : filters.keySet()) 
            student.get(key); //check if path exists
        
     catch (IllegalStateException | IllegalArgumentException ex ) 
        throw new Exception("Invalid filter parameters!");
    

    // select
    cq.select(student);
    //where
    Predicate wherePredicate = cb.and(); // init with true;
    for (Entry<String,String> filter : filters.entrySet()) 
        wherePredicate = cb.and(wherePredicate,
                                cb.like(student.get(filter.getKey()), "%"+filter.getValue()+"%"));
               
    cq.where(wherePredicate);

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

当然,like 条件不适用于IntegerDate如何扩展我的代码以根据属性数据类型定义标准?

我试过这个,不幸的是在 Java 中是不可能的:

switch (student.get(filter.getKey()).getClass()) 
    case Path<String>.class:
         return cb.like(student.get(filter.getKey()), "%"+filter.getValue()+"%");
    case Path<Integer>.class:
         return cb.equal(student.get(filter.getKey()), filter.getValue())

【问题讨论】:

【参考方案1】:

这不是最好的方法,但您可以只使用简单的类名称:

String className= student.get(filter.getKey()).getClass().getSimpleName();
switch (className) 
   case "Integer":
       return cb.equal(student.get(filter.getKey()), filter.getValue())
   case "String":
       return cb.like(student.get(filter.getKey()), "%"+filter.getValue()+"%");

【讨论】:

getSimpleName() 返回 SingularAttributePath 而不是通用值 &lt;T&gt; @Thanthla 什么返回 pdat.get(filter.getKey())?对于字符串、整数和日期过滤器? 返回一个Path类型的Object,其中T是学生属性的数据类型。 @Thanthla 能否请您发送方法 student.get() 的实现?这个方法在别的地方用过吗? Root&lt;Student&gt; student = cq.from(Student.class); 是 CriteriaBuilder 中的一个类。 student.get(...) 返回属性的路径。见:docs.oracle.com/javaee/6/api/javax/persistence/criteria/…

以上是关于CriteriaBuilder:在运行时根据 DataType 创建 Criteria的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 JPA CriteriaBuilder 按返回的唯一数据列排序?

使用 CriteriaBuilder 的 JPA 计数(*)。如何使用 CriteriaBuilder 检索 count(*) 列

在 criteriaBuilder 加入不想正常工作

如何使 CriteriaBuilder 加入自定义“开启”条件?

CriteriaBuilder - 倒置 LIKE

实体列表的 CriteriaBuilder 和 isMember (Hibernate)