我希望找到最简单的解决方案,在这种情况下你有一个查询方法,它接受一个实体的某些属性,并根据该属性执行返回该实体的查询。
问题是,如果我想添加更多可以搜索实体的属性,使用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。我不希望这种方法需要多个参数。
答案 0 :(得分:0)
我有点惊讶这个问题以前没有在这里讨论过。
所以我做了一些调查,得出了可能的答案。
最简单的方法是拥有一个单独的类f.x. CarSearchFilter,您可以在其中使用各种过滤器(即您要执行查询的参数):
public class CarSearchFilter {
private String name;
private Date date;
private String color;
//etc
//getters and setters
}
这样,当您想要添加新参数进行查询时,只需向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;
}
还有其他方法可以完成此任务。正如Tiny建议的那样,可以使用键/值对机制来存储搜索过滤器,使用键作为属性/字段名称和值作为字段值,但这种方法有一些缺点: