简体   繁体   English

Spring 数据 JPA 投影与多对一

[英]Spring Data JPA projection with ManyToOne

I have the following two entities:我有以下两个实体:

@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
}

I want to generate a JPQL query in a Spring Data JPA repository which gives me the authors with all their comments.我想在 Spring 数据 JPA 存储库中生成一个 JPQL 查询,它为我提供了作者的所有评论。 My projection is我的投影是

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

and my JPQL query is我的 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> { 
}

This generates the following raw SQL query via Hibernate (Underlying DB is PostgreSQL):这将通过 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)

My test data consists of one Author with two Comments.我的测试数据由一位作者和两条评论组成。 Unfortunately, when I run this, I always get two authors (which is actually the same Author) with one comment each.不幸的是,当我运行它时,我总是得到两个作者(实际上是同一个作者),每个作者都有一个评论。 This is of course how the DB returns each row (the raw SQL looks nice and how it should be).这当然是数据库返回每一行的方式(原始 SQL 看起来不错,应该是这样)。 Is it possible for either Hibernate or Spring Data JPA (or whichever is responsible) to merge all comments into the list, or do I need to write Java code which merges the rows based on the author id? Is it possible for either Hibernate or Spring Data JPA (or whichever is responsible) to merge all comments into the list, or do I need to write Java code which merges the rows based on the author id?

If possible, I would like to have the DB perform all the data transformation already and have a nicely structured Projection as output from the query.如果可能的话,我想让数据库已经执行所有数据转换,并从查询中获得一个结构良好的投影,如 output。

My test for demonstration is:我的演示测试是:

@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())
        );
    }
}

which gives the following output:这给出了以下 output:

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

And run directly in PostgreSQL, it gives:并直接在 PostgreSQL 中运行,它给出:

 col_0_0_ | col_1_0_ |    col_2_0_
----------+----------+----------------
        1 | John Doe | First comment
        1 | John Doe | Second comment
(2 rows)

My expected Java output is:我预期的 Java output 是:

John Doe, [First comment, Second comment]

Is this even possible with JPA? JPA 甚至可能吗?

Use relation in Author entity to fetch comments of author.Author实体中使用关系来获取作者的评论。

@OneToMany(mappedBy = "author")
private List<Comment> comments = new ArrayList<>();

Then query this way然后这样查询

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

And projection like和投影一样

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

You get all the comments by just query the authors.您只需查询作者即可获得所有评论。 You need to add extra List in Author class.您需要在作者 class 中添加额外的列表。

@OneToMany(mappedBy = "author", fetch=FetchType.LAZY)
private List<Comment> comments = new ArrayList<>();

Then, you can use JAP Reposity然后,您可以使用 JAP Reposity

@Repository
public interface AuthorRepository  extends CrudRepository<Author, Long> {

}

CrudRepository already implement many useful API, such as findAll() , findById() , you don't need to write any sqls. CrudRepository已经实现了很多有用的 API,比如findAll()findById() ,你不需要写任何 sql。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM