如何避免Hibernate Projection的多个数据库查询?

时间:2015-03-30 02:01:18

标签: java 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完整的复制品供任何人试用。

2 个答案:

答案 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 ?)

子查询减少了往返次数,但仍然可能不是在数据库上执行的最有效查询。