我有两个具有单向多对一关系的类。使用投影基于另一个类的标准查询其中一个类会生成额外的查询(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完整的复制品供任何人试用。
答案 0 :(得分:0)
尝试
_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必须包含公共getter和setter以及公共构造函数
答案 1 :(得分:0)
可以使用子查询:
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 ?)
子查询减少了往返次数,但仍然可能不是在数据库上执行的最有效查询。