将参数添加到条件查询的最简单方法

时间:2014-10-30 18:50:03

标签: java jpa 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;
    }

如果我想以我可以通过其他属性搜索Car实体的方式扩展此查询,我该怎么办,例如Date。我不希望这种方法需要多个参数。

1 个答案:

答案 0 :(得分:0)

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

所以我做了一些调查,得出了可能的答案。

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

public class CarSearchFilter {

    private String name;
    private Date date;
    private String color;
    //etc

//getters and setters

}

这样,当您想要添加新参数进行查询时,只需向CarSearhFilter添加新字段并修改查询方法即可。如果您不修改查询方法,它仍然可以按原样运行。 API以这种方式看起来很好。因此,必须以这种方式修改find​​Car方法:

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;
}

还有其他方法可以完成此任务。正如Tiny建议的那样,可以使用键/值对机制来存储搜索过滤器,使用键作为属性/字段名称和值作为字段值,但这种方法有一些缺点:

  • 地图是硬编码的
  • 您必须将密钥存储在某处
  • 可以完成迷雾