在Hibernate中使用编程条件创建查询的最佳方法
假设我有一个方法负责根据传递给它的参数构建查询:在Hibernate中使用编程条件创建查询的最佳方法,hibernate,criteria,named-parameters,Hibernate,Criteria,Named Parameters,假设我有一个方法负责根据传递给它的参数构建查询: public Query<User> buildQuery(String name, String city) { Session session = HibernateUtil.getSessionFactory().openSession(); String queryString = "from Users where 1 = 1 "; if (name != null)
public Query<User> buildQuery(String name, String city) {
Session session = HibernateUtil.getSessionFactory().openSession();
String queryString = "from Users where 1 = 1 ";
if (name != null) queryString += "and name = :name ";
if (city != null) queryString += "and city = :city ";
Query<User> query = session.createQuery(queryString, User.class);
if (name != null) query.setParameter("name", name);
if (city != null) query.setParameter("city", city);
return query;
}
公共查询buildQuery(字符串名称,字符串城市){
Session Session=HibernateUtil.getSessionFactory().openSession();
字符串queryString=“来自用户,其中1=1”;
如果(name!=null)queryString+=“和name=:name”;
如果(city!=null)queryString+=“和city=:city”;
Query=session.createQuery(queryString,User.class);
if(name!=null)query.setParameter(“name”,name);
if(city!=null)query.setParameter(“city”,city);
返回查询;
}
我不喜欢这样,因为逻辑重复了两次(用于添加条件和设置参数)
我想到的唯一解决方案是使用条件查询:
public Query<User> buildQuery2(String name, String city) {
Session session = HibernateUtil.getSessionFactory().openSession();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<User> criteriaQuery = builder.createQuery(User.class);
Root<User> root = criteriaQuery.from(User.class);
Predicate predicate = builder.conjunction();
if (name != null) {
predicate = builder.and(predicate, builder.equal(root.get("name"), name));
}
if (city != null) {
predicate = builder.and(predicate, builder.equal(root.get("city"), city));
}
criteriaQuery.select(root).where(predicate);
Query<User> query = session.createQuery(criteriaQuery);
return query;
}
公共查询buildQuery2(字符串名称,字符串城市){
Session Session=HibernateUtil.getSessionFactory().openSession();
CriteriaBuilder=session.getCriteriaBuilder();
CriteriaQuery CriteriaQuery=builder.createQuery(User.class);
Root=criteriaQuery.from(User.class);
谓词=builder.conjunction();
if(name!=null){
谓词=builder.and(谓词,builder.equal(root.get(“name”),name));
}
如果(城市!=null){
谓词=builder.and(谓词,builder.equal(root.get(“city”),city));
}
选择(根)。其中(谓词);
Query Query=session.createQuery(criteriaQuery);
返回查询;
}
有更好的解决方案吗?JPA Criteria API方法是一种方法,但是添加新的过滤器将需要更改您的业务代码,这不是很理想。此外,在某些情况下,将所有可能的筛选值列为方法的参数是非常痛苦的 我建议你看看能提供什么 我创建了这个库,以便在JPA模型和自定义接口定义的模型之间进行轻松映射,类似于类固醇上的Spring数据投影。其思想是以您喜欢的方式定义目标结构,并通过JPQL表达式将属性(getter)映射到实体模型。由于属性名被用作默认映射,您基本上不需要显式映射,因为80%的用例都需要DTO作为实体模型的子集。最好的是,您可以为投影定义过滤器 您的模型的映射可以看起来像下面这样简单
@EntityView(User.class)
interface UserView {
@IdMapping
Long getId();
@AttributeFilter(EqualFilter.class)
String getName();
@AttributeFilter(EqualFilter.class)
String getCity();
}
在表示层中,您可以构建一个EntityViewSetting
对象,您可以将其传递到服务层
EntityViewSetting<UserView, CriteriaBuilder<UserView>> setting = EntityViewSetting.create(UserView.class);
if (nameFilter != null) setting.addAttributeFilter("name", nameFilter);
if (cityFilter != null) setting.addAttributeFilter("city", cityFilter);
EntityViewSetting=EntityViewSetting.create(UserView.class);
if(nameFilter!=null)设置.addAttributeFilter(“name”,nameFilter);
if(cityFilter!=null)setting.addAttributeFilter(“city”,cityFilter);
然后,您的服务可以是纯业务逻辑的,类似这样的
<T> T findAll(EntityViewSetting<T, CriteriaBuilder<T>> setting) {
CriteriaBuilder<User> cb = criteriaBuilderFactory.create(entityManager, User.class);
// Your business logic
return entityViewManager.applySetting(setting, cb);
}
T findAll(实体视图设置){
CriteriaBuilder cb=criteriaBuilderFactory.create(entityManager,User.class);
//您的业务逻辑
返回entityViewManager.applySetting(设置,cb);
}
谢谢你的回答,我肯定会调查Blaze,但目前我必须坚持纯Hibernate。你能详细介绍一下这个话题吗?你对JPA标准API的使用还可以。你有什么特别的方法不起作用吗?我的解决方案非常有效,我只是想知道其他方法是否更好。谢谢