我在使用DTO对象时正在进行N + 1 SELECTS的hibernate有问题。
例如,这个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
...
但是,如果构造函数不接受实体,而是接受每个单独的列,则hibernate的行为与您期望的一样,即:
public MyDto(Integer id, String column1, String column2) {
...
}
然后生成的SQL如下所示:
SELECT t.id, t.column1, t.column2 FROM thing t WHERE condition
除了创建占用每一列的DTO构造函数之外,还有一种方法可以让hibernate从一开始就一次选择所有列吗?
我们正在使用的表格中有100多个列分布在嵌入式文件中,因此维护庞大的构造函数非常烦人。该表非常规范化,没有连接。
答案 0 :(得分:1)
第一次读错了你的问题...我不记得使用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应该一次性获取所有需要的行
答案 1 :(得分:0)
您可能已经注意到,构造函数表达式方法有很多缺点。如果您需要嵌套的关联,它将变得更糟。这里使用实体对象的主要问题是您仍然可能会遇到N + 1个查询问题。不久前,我就该主题写过blog post,证明了我创建Blaze-Persistence Entity Views的原因,informatica read rest api是一个允许将DTO映射为接口的库。