JPA 将查询中选定的 OneToMany 列表作为投影结果中的单个 Java 对象返回

问题描述 投票:0回答:1

我有一个与这个问题类似的设置,即一个作者可以有多个评论。在我的例子中,它在 Author 类上被建模为 OneToMany。

@Entity
public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userName;

    @OneToMany()
    @JoinTable(name = "AUTHOR_COMMENTS")
    private List<Comment> comments;
}

JPA 创建了一个引用表来实现这种关系,因此有了

@JoinTable
注释。

现在,我想在单个查询中查询作者及其所有评论。

来自here的答案表明,通过选择查询中的注释列表,这应该可以在 JPQL 中实现。

@Query(value= "SELECT a.userName as userName, a.comments as comments from Author a")
List<AuthorProjection> authorsWithComments();

请注意,在我的例子中,结果被投影到相关字段。

public interface AuthorProjection {
    String getUserName();
    List<CommentProjection> getComments();
}

问题是 JPA 仅返回列表中的单个评论。

我得到:

John Doe, [First comment]
John Doe, [Second comment]

但我想要:

John Doe, [First comment, Second comment]

因此,我希望所有评论都返回到相应作者的列表中,全部只使用一个查询。

  • 这可能吗?
  • 我需要配置什么吗(我使用H2数据库)?
  • 领域模型是否有使其工作的要求(例如,需要从评论到作者的反向引用)?

我发现其他答案提到

JOIN FETCH
SELECT NEW
。但我无法让它与 JOIN FETCH 一起工作。而且 SELECT NEW 似乎不适用,因为我已经使用了投影界面。

jpa select spring-data-jpa one-to-many projection
1个回答
0
投票

正如评论中所指出的,选择这样的整个对象列表是不可能的。

但根据要求,可以使用数据库特定的聚合函数来选择一个附加列来聚合子查询的值。

对于上面的示例,字符串连接聚合函数(例如 PostgreSQL 中的 STRING_AGG)可能是一个可行的解决方案:

SELECT
    a.userName as userName,
    (SELECT STRING_AGG(c.text, ",") FROM Comment c WHERE c MEMBER OF a.comments) as commentTextCsv
FROM Author a

请注意,上面的示例使用 JPA 的 MEMBER OF 运算符来检查当前评论是否在作者的评论列表中。另一种方法是使用 IN 运算符和子查询来检查当前评论的 ID 是否在作者的评论 ID 列表中。

© www.soinside.com 2019 - 2024. All rights reserved.