[Java][Hibernate]如何获取子依赖项集合的限制?
我将SpringBoot与Hibernate和JPA一起使用 我有三个实体Device、ErrorType和ErrorRecord,它们之间的关系为一对多,如下图所示 现在,当我得到一个设备时,我想得到它的错误类型列表。对于每种错误类型,我只想得到一个最新的错误记录(如果有的话) 这是我目前的代码: ErrorType.java @实体 @表B错误类型 类错误类型{ ... @OrderByvalue=createAt DESC @OneToNameAppedby=errorType,cascade=CascadeType.ALL @Cacheusage=CacheConcurrentyStrategy.NONSTRICT\u READ\u WRITE 私有集错误=新LinkedHashSet; ... } ErrorRecord.java @实体 @表B错误记录 类错误记录{ ... @许多酮 @JoinColumnname=错误类型id 私有错误类型错误类型; ... } ErrorTypeRepository.java @QuerySELECT DISTINCT e FROM ErrorType e LEFT JOIN FETCH e.errors其中e.device.id=:deviceId ORDER BY e.ErrorType 列表findErrorTypesByDeviceIdEagerErrorRecords@ParamrobotIdUUID机器人; ErrorTypeService.java @TransactionalreadOnly=true 公共列表FindAlluid设备ID{ 返回errorTypeRepository.FinderRorTypesByDeviceId错误记录DeviceId.stream.maperrorType->{ ErrorTypeDTO dto=新的ErrorTypeDTO; //这里有些能手和二传手 如果errorType.getErrors!=null&&!errorType.getErrors.isEmpty{ dto.setLatestErrorerrorType.getErrors.get0; } }.collectCollectors.toCollectionLinkedList::新建; } 目前,它可以正确地处理数据。但是,由于ErrorRecord中的数据增长迅速,因此每个ErrorType中可能有多达数百万个ErrorRecord。在这种情况下,此API的性能太慢且超时 预期:我只想按createAt加载一条记录,加载所有errorType时,在获取的子错误中限制1 我可以先加载所有ErrorType,然后循环遍历ErrorType列表。对于每个errorType,进行查询以获取最新的errorRecords。但这似乎是一种性能不好的方法,这造成了大量对数据库n+1的查询问题[Java][Hibernate]如何获取子依赖项集合的限制?,hibernate,jpa,jpql,Hibernate,Jpa,Jpql,我将SpringBoot与Hibernate和JPA一起使用 我有三个实体Device、ErrorType和ErrorRecord,它们之间的关系为一对多,如下图所示 现在,当我得到一个设备时,我想得到它的错误类型列表。对于每种错误类型,我只想得到一个最新的错误记录(如果有的话) 这是我目前的代码: ErrorType.java @实体 @表B错误类型 类错误类型{ ... @OrderByvalue=createAt DESC @OneToNameAppedby=errorType,casca
在研究了Hibernate查询表达式之后,我仍然不知道如何限制子集合中的记录数。从中可以看出,获取最后一条错误记录并不是一项简单的任务。据我所知,使用JPA映射映射这样的东西是不可能的。这更适合于特定的操作,如FinderRorTypesByDeviceIdErrorRecords 同样,这样的查询也不能用JPQL编写,只能用本机SQL编写。例如,使用,它将类似于: FluentQuery query=FluentJPA.SQLErrorType errorType->{ OrderedErrorRecord orderedRec=子查询错误记录错误记录->{ 别名rn=别名聚合比罗编号 .OVERPARTITIONBYerrorRec.getErrorType.getId .ORDERBYerrorRec.getCreatedAt.DESC, OrderedErrorRecord::getRowNumber; 选择errorrec,rn; FROMerrorRec; }; 与OrderedRec; 选择ErrorType,orderedRec.getErrorDescription; FROMerrorType.LEFT_JOINorderedRec .ONorderedRec.getErrorType==errorType&&orderedRec.getRowNumber==1; 其中ErrorType.getDevice.getId==deviceId; }; 返回query.createQueryem,ErrorTypeWithLastError.class.getResultList; 这将生成以下SQL:
WITH q0 AS
(SELECT t1.*, ROW_NUMBER() OVER(PARTITION BY t1.error_type_id
ORDER BY t1.created_at DESC ) AS row_number
FROM tbl_error_record t1 )
SELECT t0.*, q0.error_description
FROM tbl_error_type t0 LEFT JOIN q0 ON ((q0.error_type_id = t0.id) AND (q0.row_number = 1))
WHERE (t0.device_id = ?1)
请注意,我选择了其他字段,而不是在ErrorType中声明的字段,因此需要一个DTO投影来映射它们。我们还需要OrderedErrorRecord来保存行号。因此,宣布了另外两个类别:
@元组
@Getter//lombok
公共静态类OrderedErrorRecord扩展了ErrorRecord{
私有整数行数;
}
@元组
@Getter//lombok
公共静态类ErrorTypeWithLastError扩展了ErrorType{
@嵌入
私有错误内容错误内容;
}