繁体   English   中英

使用DTO对象休眠N + 1 SELECT

[英]Hibernate N+1 SELECTs with DTO objects

我在使用DTO对象时在进行N + 1选择的休眠状态下遇到问题。

例如,此JPQL查询:

SELECT com.acme.MyDto(t) FROM Thing t

MyDto的构造函数如下所示:

public MyDto(Thing t) {
   ...
}

结果查询如下:

SELECT t.id FROM thing t WHERE condition

随后是每一行的所有单个查询,即:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 1
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 2
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 3
...

但是,如果构造函数不接受Entity,而是接受每个单独的列,则冬眠的行为将与您期望的一样,即:

public MyDto(Integer id, String column1, String column2) {
   ...
}

然后,生成的SQL如下所示:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE condition

除了创建占用每一列的DTO构造函数之外,还有没有一种方法可以让休眠模式从一开始就一次选择所有列?

我们正在使用的表在可嵌入对象中分布了100多个列,因此维护一个巨大的构造函数很烦人。 该表已被高度规范化,并且没有联接。

第一次读错您的问题...我不记得使用DTO来获取整个实体,而不仅仅是一些特定的列,所以我不确定为什么当您将整个实体用作对象时,Hibernate的行为会如此DTO构造函数中的参数。 无论如何,您可以通过查询获取实际Things来解决此问题,然后在循环中构造DTO,类似于以下内容:

public List<ThingDTO> getThingDTOs( ... )
{
    Query query = em().createQuery("FROM Thing t WHERE ...");
    query.setParameter( ... );

    List<Thing> things = query.getResultList();

    List<ThingDTO> thingDTOs = new ArrayList(things.size());
    for(Thing t : things)
    {
        thingDTOs.add(new ThingDTO(t));
    }

    return thingDTOs
}

这不是很漂亮,但是这种方式Hibernate应该一次性获取所有需要的行

您可能已经注意到,构造函数表达式方法有很多缺点。 如果您需要嵌套的关联,它将变得更糟。 这里使用实体对象的主要问题是您仍然可能会遇到N + 1个查询问题。 不久前,我就该主题写了一篇博客文章 ,论证了为什么我创建了Blaze-Persistence Entity Views的理由,该视图允许将DTO映射为接口。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM