【发布时间】:2020-04-30 13:12:36
【问题描述】:
我有以下两个实体:
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String userName;
// Getters/setters
}
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "author_id")
private Author author;
private String comment;
// Getters/setters
}
我想在 Spring Data JPA 存储库中生成一个 JPQL 查询,它为我提供了作者所有的 cmets。我的投影是
public interface AuthorProjection {
String getUserName();
List<String> getComments();
}
我的 JPQL 查询是
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Query(value= "SELECT a.id as id, \n" +
" a.userName as userName,\n" +
" c.comment as comments\n" +
"from Author a \n" +
"left join Comment c on c.author = a")
List<AuthorProjection> authorsWithComments();
}
public interface CommentRepository extends JpaRepository<Comment, Long> {
}
这会通过 Hibernate 生成以下原始 SQL 查询(底层数据库是 PostgreSQL):
select author0_.id as col_0_0_, author0_.user_name as col_1_0_,comment1_.comment as col_2_0_ from author author0_ left outer join comment comment1_ on (comment1_.author_id=author0_.id)
我的测试数据由一个作者和两个评论组成。不幸的是,当我运行它时,我总是得到两个作者(实际上是同一个作者),每个作者都有一个评论。这当然是数据库返回每一行的方式(原始 SQL 看起来不错,应该是这样)。 Hibernate 或 Spring Data JPA(或任何负责人)是否可以将所有 cmets 合并到列表中,还是我需要编写 Java 代码来根据作者 ID 合并行?
如果可能,我希望数据库已经执行所有数据转换,并有一个结构良好的投影作为查询的输出。
我的演示测试是:
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class JpatestApplicationTests {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private CommentRepository commentRepository;
@Test
void contextLoads() {
var author = new Author();
author.setUserName("John Doe");
var savedAuthor = authorRepository.save(author);
var comment1 = new Comment();
comment1.setComment("First comment").setAuthor(savedAuthor);
commentRepository.save(comment1);
var comment2 = new Comment();
comment2.setComment("Second comment").setAuthor(savedAuthor);
commentRepository.save(comment2);
authorRepository.authorsWithComments().forEach(
projection -> System.out.printf("%s, %s\n", projection.getUserName(), projection.getComments())
);
}
}
给出以下输出:
John Doe, [First comment]
John Doe, [Second comment]
并直接在 PostgreSQL 中运行,它给出:
col_0_0_ | col_1_0_ | col_2_0_
----------+----------+----------------
1 | John Doe | First comment
1 | John Doe | Second comment
(2 rows)
我预期的 Java 输出是:
John Doe, [First comment, Second comment]
JPA 甚至可以做到这一点吗?
【问题讨论】:
-
你能添加你的原始 sql 查询吗?
-
我已经用一个简单的工作示例对其进行了更新。
标签: java spring-data-jpa jpql