Java 带多通的Spring数据JPA投影
我有以下两个实体:Java 带多通的Spring数据JPA投影,java,spring-data-jpa,jpql,Java,Spring Data Jpa,Jpql,我有以下两个实体: @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String userName; // Getters/setters } @Entity public class Comment { @Id @GeneratedValue(strategy
@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
}
我想在SpringDataJPA存储库中生成一个JPQL查询,它为我提供作者及其所有评论。我的预测是
public interface AuthorProjection {
String getUserName();
List<String> getComments();
}
我的测试数据由一位作者和两位注释组成。不幸的是,当我运行这个程序时,我总是得到两个作者(实际上是同一个作者),每个作者都有一条评论。这当然是DB返回每一行的方式(原始SQL看起来不错,应该是这样的)。Hibernate或Spring Data JPA(或任何负责人)是否可以将所有注释合并到列表中,或者我是否需要编写基于作者id合并行的Java代码
如果可能的话,我希望DB已经执行了所有的数据转换,并且有一个结构良好的投影作为查询的输出
我的演示测试是:
@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甚至可以这样做吗?使用
作者
实体中的关系来获取作者的评论
@OneToMany(mappedBy = "author")
private List<Comment> comments = new ArrayList<>();
@OneToMany(mappedBy=“author”)
私有列表注释=新建ArrayList();
那么这样问吧
@Query(value= "SELECT a.userName as userName, a.comments as comments from Author a")
List<AuthorProjection> authorsWithComments();
@Query(value=“选择a.userName作为用户名,a.comments作为作者a的注释”)
使用注释()列出作者;
和投影一样
public interface AuthorProjection {
String getUserName();
List<Comment> getComments();
}
公共接口AuthorProjection{
字符串getUserName();
List getComments();
}
您只需查询作者即可获得所有评论。您需要在Author类中添加额外的列表
@OneToMany(mappedBy=“author”,fetch=FetchType.LAZY)
私有列表注释=新建ArrayList();
然后,您可以使用JAP Reposity
@存储库
公共接口AuthorRepository扩展了crudepository{
}
crudepository
已经实现了许多有用的API,例如findAll()
,findById()
,您不需要编写任何sql。您可以添加原始sql查询吗?我用一个简单的工作示例对其进行了更新。在不更改实体的情况下也可以这样做吗?我的实际查询像这样复杂得多,我不想改变实体。但是我想让数据库做尽可能多的工作。如果你不使用关系,那么JPA如何为作者整合所有评论。您的查询在加入后返回笛卡尔乘积,这就是为什么您只得到一条注释。或者,您必须手动集成作者的所有评论。您尝试过此解决方案吗?我不能,因为没有任何关系,而且我无法说服我的同事让我添加它:-(.最后,我创建了一个事务性@Service方法,在这里我调用了多个存储库,并用Java聚合了结果。我确实想在JPQL中完全尝试,但最后我只需要结果。不过,感谢您的帮助!
@Query(value= "SELECT a.userName as userName, a.comments as comments from Author a")
List<AuthorProjection> authorsWithComments();
public interface AuthorProjection {
String getUserName();
List<Comment> getComments();
}