如何避免对 Hibernate Projection 进行多次数据库查询?
How to avoid multiple database queries for Hibernate Projection?
我有两个 类 具有单向多对一关系。根据另一个投影的条件查询 类 之一会生成额外的查询 (n+1)。 使用Hibernate,一个投影查询如何避免n+1个查询?
这是我的模型:
@Entity
public class Person {
@ManyToOne(targetEntity=PersonType.class, optional=false)
private PersonType personType;
@Id
@GeneratedValue
private Long id;
private String name;
/* other supporting code */
}
@Entity
public class PersonType {
@Id
@GeneratedValue
private Long id;
/* other supporting code */
}
这是我的条件查询
session.createCriteria(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.setProjection(Projections.distinct(Projections.property("personType")))
.list()
;
这里是 运行 条件的 Hibernate 日志:
Hibernate: select distinct this_.personType_id as y0_ from Person this_ where this_.name like ?
Hibernate: select persontype0_.id as id1_0_, persontype0_.name as name1_0_ from PersonType persontype0_ where persontype0_.id=?
Hibernate: select persontype0_.id as id1_0_, persontype0_.name as name1_0_ from PersonType persontype0_ where persontype0_.id=?
Hibernate 执行查询以获取 PersonType
个 ID,然后分别查询每个 PersonType
。这些往返是网站请求的昂贵部分,我想避免它们。
我在 github 上有 published 的完整复制品供任何人试验。
尝试
_sessionFactory.getCurrentSession().createCriteria(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.createAlias("personType", "personType")
.setProjection(
Projections.projectionList().add(
Projections.distinct(Projections
.property("personType.id")), "id").add(Projections
.property("personType.name"), "name"))
.setResultTransformer(Transformers.aliasToBean(PersonType.class))
.list();
PersonType 必须有 public 个 getter 和 setter 以及一个 public 构造函数
可以使用子查询:
DetachedCriteria subquery = DetachedCriteria.forClass(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.setProjection(Projections.distinct(Projections.property("personType.id")))
;
return session.createCriteria(PersonType.class)
.add(Subqueries.propertyIn("id", subquery))
.list()
;
这是生成的查询:
Hibernate: select this_.id as id1_0_, this_.name as name1_0_ from PersonType this_ where this_.id in (select distinct this_.personType_id as y0_ from Person this_ where this_.name like ?)
子查询减少了往返次数,但仍可能不是在数据库上执行的最有效查询。
我有两个 类 具有单向多对一关系。根据另一个投影的条件查询 类 之一会生成额外的查询 (n+1)。 使用Hibernate,一个投影查询如何避免n+1个查询?
这是我的模型:
@Entity
public class Person {
@ManyToOne(targetEntity=PersonType.class, optional=false)
private PersonType personType;
@Id
@GeneratedValue
private Long id;
private String name;
/* other supporting code */
}
@Entity
public class PersonType {
@Id
@GeneratedValue
private Long id;
/* other supporting code */
}
这是我的条件查询
session.createCriteria(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.setProjection(Projections.distinct(Projections.property("personType")))
.list()
;
这里是 运行 条件的 Hibernate 日志:
Hibernate: select distinct this_.personType_id as y0_ from Person this_ where this_.name like ?
Hibernate: select persontype0_.id as id1_0_, persontype0_.name as name1_0_ from PersonType persontype0_ where persontype0_.id=?
Hibernate: select persontype0_.id as id1_0_, persontype0_.name as name1_0_ from PersonType persontype0_ where persontype0_.id=?
Hibernate 执行查询以获取 PersonType
个 ID,然后分别查询每个 PersonType
。这些往返是网站请求的昂贵部分,我想避免它们。
我在 github 上有 published 的完整复制品供任何人试验。
尝试
_sessionFactory.getCurrentSession().createCriteria(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.createAlias("personType", "personType")
.setProjection(
Projections.projectionList().add(
Projections.distinct(Projections
.property("personType.id")), "id").add(Projections
.property("personType.name"), "name"))
.setResultTransformer(Transformers.aliasToBean(PersonType.class))
.list();
PersonType 必须有 public 个 getter 和 setter 以及一个 public 构造函数
可以使用子查询:
DetachedCriteria subquery = DetachedCriteria.forClass(Person.class)
.add(Restrictions.like("name", "%" + nameContains + "%"))
.setProjection(Projections.distinct(Projections.property("personType.id")))
;
return session.createCriteria(PersonType.class)
.add(Subqueries.propertyIn("id", subquery))
.list()
;
这是生成的查询:
Hibernate: select this_.id as id1_0_, this_.name as name1_0_ from PersonType this_ where this_.id in (select distinct this_.personType_id as y0_ from Person this_ where this_.name like ?)
子查询减少了往返次数,但仍可能不是在数据库上执行的最有效查询。