hibernate示例
尽管当前&nbps;的趋势 对于ORM框架,使用JPA或Hibernate从来没有任何问题。 我必须承认我的用例非常简单。 另外,由于那是几年前的事,我们将这些应用程序托管在我们自己的现场基础架构上,因此,寻求最终性能及其相关的节省并不是目标。 为不熟悉许多技术的初级开发人员赋权。
有趣的是,Hibernate实际上早于JPA,因此该实现具有比规范更多的功能:在JPA 1.0中非常明显,而在2.0中则更少。 但是,无论差距多么小,它都存在。 遗憾的是,因为Hibernate在JPA无法匹配的某些领域提供了非常好的API。 这样的领域之一就是查询,它的相关功能是按示例查询。 这篇文章专门描述这种用例的上下文,以及如何 QBE有助于轻松解决它。
回到JPA 1.0, JPQL 是执行查询的唯一选择。 在当前版本(2.1)之前仍然可用,并且大量借鉴了SQL语法。
例如,从PERSON
表中的所有实体中选择所有字段将转换为以下JPQL查询:
SELECT p FROM Person p
添加搜索条件同样与SQL非常相似:
SELECT p FROM Person p WHERE firstName = 'Doe'
使用JPQL实施以前的搜索表单需要:
评估结果如下:
@WebServlet("/jpql")
classJpqlServlet:HttpServlet(){
overridefundoPost(req:HttpServletRequest,resp:HttpServletResponse){
doAndDispatch(req,resp){firstName,lastName,birthdate,em-> (1)
valselect="SELECT p FROM Person p"
valjpql=if(firstName.isBlank() (2)
&&lastName.isBlank()
&&birthdate==null)select
else{
valwhere="$select WHERE" (3)
varexpression=where
if(firstName.isNotBlank())
expression+=" firstName = '$firstName'" (4)
if(lastName.isNotBlank()){
if(expression!=where) (5)
expression+=" AND" (6)
expression+=" lastName = '$lastName'"
}
if(birthdate!=null){
if(expression!=where)
expression+=" AND"
expression+=" birthdate = '$birthdate'"
}
expression
}
valcq=em.createQuery(jpql)
cq.resultList
}
}
}
SELECT
,没有WHERE
子句 WHERE
子句 WHERE
子句 AND
子句 对于好奇的读者,这是doAndDispatch()
函数的代码。 它还将用于替代实现中。
privatefundoAndDispatch(req:HttpServletRequest,
resp:HttpServletResponse,
f:(String,String,LocalDate?,EntityManager)->List<*>){
funString.toLocaleDate():LocalDate?=if(this.isBlank())null
elseLocalDate.parse(this)
valfirstName=req.getParameter("firstName")
vallastName=req.getParameter("lastName")
valbirthdate=req.getParameter("birthdate")?.toLocaleDate()
valem=Persistence.emf.createEntityManager()
valpersons=f(firstName,lastName,birthdate,em)
req.setAttribute("persons",persons)
req.setAttribute("firstName",firstName)
req.setAttribute("lastName",lastName)
req.setAttribute("birthdate",birthdate)
req.getRequestDispatcher("/WEB-INF/persons.jsp").forward(req,resp)
}
显然,在此用例中使用JPQL很复杂且容易出错:这是非类型安全API( 例如字符串连接)的问题。 为了解决这个问题,JPA 2.0引入了Criteria API,它提供了一种强类型的API。
上面的SELECT
查询可以替换为以下内容:
valcq=em.criteriaBuilder.createQuery(Person::class.java)
cq.from(Person::class.java)
valtypedQuery=em.createQuery(cq)
typedQuery.resultList
尽管实际上没有WHERE
子句的查询需要更多代码,但在WHERE
,Criteria API会更好:
valcq=em.criteriaBuilder.createQuery(Person::class.java)
valperson=cq.from(Person::class.java)
cq.where(em.criteriaBuilder.equal(person.get<String>("lastName"),"Doe"))
valtypedQuery=em.createQuery(cq)
typedQuery.resultList
关于搜索表单用例,可以看到使用Criteria API的好处。 评估字段是否已填充的逻辑保持不变,但是添加条件变得容易得多:
doAndDispatch(req,resp){firstName,lastName,birthdate,em->
valcq=em.criteriaBuilder.createQuery(Person::class.java)
valperson=cq.from(Person::class.java)
varpredicates=listOf<Predicate>()
if(firstName.isNotBlank())
predicates=predicates+
em.criteriaBuilder.equal(person.get<String>("firstName"),firstName)
if(lastName.isNotBlank())
predicates=predicates+
em.criteriaBuilder.equal(person.get<String>("lastName"),lastName)
if(birthdate!=null)
predicates=predicates+
em.criteriaBuilder.equal(person.get<LocalDate>("birthdate"),birthdate)
cq.where(*predicates.toTypedArray())
valquery=em.createQuery(cq)
query.resultList
}
为了实施更强的键入,可以生成JPA元模型。 由于规范未涵盖元模型的生成,因此请检查您的ORM实现的文档。
在Hibernate 4.x中,一个名为Query-By-Example的漂亮功能非常适合搜索用例。 要使用它只是一个问题:
相应的代码如下所示:
doAndDispatch(req,resp){firstName,lastName,birthdate,em->
valsession=em.delegateasSession (1)
valperson=Person(firstName=if(firstName.isBlank())nullelsefirstName, (2)
lastName=if(lastName.isBlank())nullelselastName,
birthdate=birthdate)
valexample=Example.create(person) (3)
valcriteria=session.createCriteria(Person::class.java).add(example)
criteria.list()
}
EntityManager
需要强制转换为专有的Hibernate的Session
,因为只有后者才提供QBE功能 null
表示该属性将不属于WHERE
子句。 因此,需要将空字符串设置为null
请注意,尽管QBE非常强大,但它也有一些限制。 如上所示,需要将空字段设置为null
。 因此,由于该示例位于Kotlin中,因此实体类属性必须从不可为null的类型更新为可为null的类型。
@Entity
classPerson(@Id@GeneratedValuevarid:Long?=null,
valfirstName:String?,
vallastName:String?,
valbirthdate:LocalDate?)
或者,可以仅出于QBE的目的创建一个专用的类。
如果有更多要求,那么总是有可能退回到上面提到的Criteria API。 就我所知,QBE做一件事,但是做得很好。
如本文所见,在实体上执行简单查询时,QBE是一项非常有用的功能。 当我最近发现Hibernate 5.x不推荐使用此功能时,我感到非常惊讶! 根据我的读物,其理由是,由于团队规模不够大,因此实现JPA规范比提供专有功能要好得多,而不管其价值如何。
QBE是否可以用于下一个JPA版本还有待观察。 恕我直言,不添加它-或将其从Hibernate中完全删除将是一个耻辱。
翻译自: https://blog.frankel.ch/hibernate-query-by-example/
hibernate示例