CriteriaBuilder: создание критериев на основе DataType во время выполнения - PullRequest
0 голосов
/ 25 января 2019

У меня есть упрощенный класс 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 не работают для Integer или Date. Как я могу расширить свой код для определения критериев, основанных на типе данных атрибутов?

Я пробовал это, что, к сожалению, невозможно в 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 Ответ

0 голосов
/ 25 января 2019

Это не лучший подход, но вы можете использовать просто простое имя класса:

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()+"%");
}
...