如何避免对 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 ?)

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