Java 向条件查询添加参数的最简单方法

Java 向条件查询添加参数的最简单方法,java,jpa,criteria,Java,Jpa,Criteria,我想找到一个最简单的解决方案,在这种情况下,您有一个查询方法,该方法获取实体的某些属性,并基于该属性执行返回该实体的查询 问题是,如果我想添加更多的属性来搜索实体,那么使用jpa标准时最简单的解决方案是什么?这里的一个方面是该方法必须是可移植的——如果我以后添加属性,我不想重写所有代码 我知道这可以通过方法重载来实现,但我正在寻找更简单的解决方案 例如,我的方法的代码是: public List<Car> findCar(String name) { Criteria

我想找到一个最简单的解决方案,在这种情况下,您有一个查询方法,该方法获取实体的某些属性,并基于该属性执行返回该实体的查询

问题是,如果我想添加更多的属性来搜索实体,那么使用jpa标准时最简单的解决方案是什么?这里的一个方面是该方法必须是可移植的——如果我以后添加属性,我不想重写所有代码

我知道这可以通过方法重载来实现,但我正在寻找更简单的解决方案

例如,我的方法的代码是:

public List<Car> findCar(String name) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Car> c = cb.createQuery(Car.class);
        Root<Car> d = c.from(Car.class);
        Predicate condition = cb.equal(d.get(Car_.name), name);
        c.where(condition);
        TypedQuery<Car> q = em.createQuery(c);
        List<Car> results = q.getResultList();

        return results;
    }
公共列表findCar(字符串名称){
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery c=cb.createQuery(Car.class);
根d=c.from(车辆等级);
谓词条件=cb.equal(d.get(Car_uu.name),name);
c、 何处(条件);
TypedQuery q=em.createQuery(c);
List results=q.getResultList();
返回结果;
}

如果我想以一种可以通过其他属性(例如日期)搜索汽车实体的方式扩展此查询,我应该怎么做。我不希望这个方法需要不止一个参数。

我有点惊讶,这个问题以前没有在这里讨论过

所以我做了一些调查,找到了可能的答案

最简单的方法是使用一个单独的类f.x.CarSearchFilter,在该类中您可以使用各种过滤器(即您希望执行查询的参数):

这样,当您想向查询添加新参数时,只需向CarSearhFilter添加新字段并修改查询方法。如果不修改查询方法,它仍将按原样工作。这样API看起来不错。因此,必须通过以下方式修改findCar方法:

public List<Car> findCar(CarSearchFilter filter) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Car> c = cb.createQuery(Car.class);
    Root<Car> d = c.from(Car.class);

    // you have to add more predicates when you want more parameters
    List<Predicate> predicates = new ArrayList<Predicate>();
    if (filter.getName() != null) {
        predicates.add(cb.like(d.get(Car_.name), filter.getName()));
    }
    if (filter.getDate() != null) {
        predicates.add(cb.lessThanOrEqualTo(d.get(Car_.date), filter.getDate()));
    }

    c.select(d).where(predicates.toArray(new Predicate[] {}));
    TypedQuery<Car> q = em.createQuery(c);
    List<Car> results = q.getResultList();

    return results;
}
公共列表findCar(CarSearchFilter过滤器){
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery c=cb.createQuery(Car.class);
根d=c.from(车辆等级);
//当需要更多参数时,必须添加更多谓词
列表谓词=新的ArrayList();
if(filter.getName()!=null){
add(cb.like(d.get(Car.name),filter.getName());
}
if(filter.getDate()!=null){
add(cb.lessThanOrEqualTo(d.get(Car.date),filter.getDate());
}
c、 选择(d).where(谓词.toArray(新谓词[]{}));
TypedQuery q=em.createQuery(c);
List results=q.getResultList();
返回结果;
}
还有其他方法可以完成这项任务。正如所建议的,可以使用键/值对机制来存储搜索过滤器,使用键作为属性/字段名,使用值作为字段值,但这种方法有一些缺点:

  • 地图是硬编码的
  • 你必须把钥匙存放在某个地方
  • 可能会造成打字错误
  • 等等
public List<Car> findCar(CarSearchFilter filter) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Car> c = cb.createQuery(Car.class);
    Root<Car> d = c.from(Car.class);

    // you have to add more predicates when you want more parameters
    List<Predicate> predicates = new ArrayList<Predicate>();
    if (filter.getName() != null) {
        predicates.add(cb.like(d.get(Car_.name), filter.getName()));
    }
    if (filter.getDate() != null) {
        predicates.add(cb.lessThanOrEqualTo(d.get(Car_.date), filter.getDate()));
    }

    c.select(d).where(predicates.toArray(new Predicate[] {}));
    TypedQuery<Car> q = em.createQuery(c);
    List<Car> results = q.getResultList();

    return results;
}