我刚刚偶然发现了Vlad Mihalcea的这篇伟大的文章,题目是《获取Spring Data JPA DTO投影的最佳方式》。它在reddit上也得到了一些不错的关注。这是一个很好的用例和合适的解决方案,我想快速展示第二种 最好的方法,这次是用jOOQ来做同样的事情。
提示: 你可以很容易地将jOOQ与Spring Data JPA一起使用,只需使用Spring Boot的jOOQ启动器,将
DataSource,然后将所有资源库查询委托给jOOQ。
我将直接跳到帖子中的分层DTO投射,将事物投射到这个类型层次中:
public record PostCommentDTO (
Long id,
String review
) {}
public record PostDTO (
Long id,
String title,
List<PostCommentDTO> comments
) {}
所以,我们会像这样使用jOOQ,使用MULTISET 值构造器。
List<PostDTO> result =
ctx.select(
POST.ID,
POST.TITLE,
multiset(
select(POST_COMMENT.ID, POST_COMMENT.REVIEW)
.from(POST_COMMENT)
.where(POST_COMMENT.POST_ID.eq(POST.ID))
).convertFrom(r -> r.map(mapping(PostCommentDTO::new)))
)
.from(POST)
.where(POST.TITLE.like(postTitle))
.fetch(mapping(PostDTO::new));
或者,使用MULTISET_AGG 聚合函数,如果这更适合你的话(如果你嵌套的集合不超过1层)。
List<PostDTO> result =
ctx.select(
POST_COMMENT.post().ID,
POST_COMMENT.post().TITLE,
multisetAgg(POST_COMMENT.ID, POST_COMMENT.REVIEW)
.convertFrom(r -> r.map(mapping(PostCommentDTO::new)))
.from(POST_COMMENT)
.where(POST_COMMENT.post().TITLE.like(postTitle))
.fetch(mapping(PostDTO::new));
这两种解决方案都是完全类型安全的,使用临时的记录转换。你改变了模式,重新生成了代码,你的代码就不再能编译了。
除了查询本身,你不需要写任何额外的基础设施逻辑。
很酷,对吗?)