如何在spring数据jpa中创建一对多映射的嵌套投影

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

我有一个具有post和post_comments表的一对多映射,我们的要求是在两个表中仅检索很少的值,并像postDTO一样以一对多映射的形式发送回调用方。下面是我们的代码。

发布实体

@Entity(name = "Post")
@Getter
@Setter
public class Post {

    @Id
    private Long id;

    private String title;

    private LocalDateTime createdOn;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true)
    private List<PostComment> comments = new ArrayList<>();

    public void addComment(PostComment comment) {
       this.comments.add(comment);
       comment.setPost(this);
    }

}

PostCommentEntity

@Getter
@Setter
public class PostComment {

    @Id
    private Long id;

    private String review;

    private LocalDateTime createdOn;

    public PostComment(String review) {
        this.review = review;
        this.createdOn = LocalDateTime.now();
    }

    @ManyToOne
    private Post post;

}

postDTO->我们需要的期望响应格式。

@Getter
@Setter
@Builder
@ToString
public class PostDTO {

    String title;

    @Builder.Default
    List<PostCommentsDTO> comments;
}

PostCommentsDTO->一对多的嵌套投影值。

@Data
@Builder
public class PostCommentsDTO {

    String review;

}

由于无法使用spring数据jpa直接实现此目的。使用替代映射实现。

PostRepository我们只需要从post表中获取标题,并从postDemo类中所需的postcomment表中获取评论,因为我们无法在单个实例中执行映射,所以我通过创建中间投影来委托Java中的映射,如下所示。

@Repository
public interface PostRepository extends JpaRepository<Post, Long> {

    @Query("SELECT p.title as title, c.review as review FROM Post p JOIN p.comments c where p.title = :title")
    List<PostCommentProjection> findByTitle(@Param("title") String title);
}

PostCommentProjection

public interface PostCommentProjection {

    String getTitle();

    String getReview();

}

然后最后是Java语言

    List<PostCommentProjection> postCommentProjections = this.postRepository.findByTitle("Post Title");

    final Function<Entry<String, List<PostComments>>, PostDTO> mapToPostDTO = entry -> PostDTO.builder()
            .title(entry.getKey()).comments(entry.getValue()).build();
    final Function<PostCommentProjection, String> titleClassifier = PostCommentProjection::getTitle;
    final Function<PostCommentProjection, PostComments> mapToPostComments = postCommentProjection -> PostComments
            .builder().review(postCommentProjection.getReview()).build();
    final Collector<PostCommentProjection, ?, List<PostComments>> downStreamCollector = Collectors
            .mapping(mapToPostComments, Collectors.toList());

    List<PostDTO> postDTOS = postCommentProjections.stream()
            .collect(groupingBy(titleClassifier, downStreamCollector)).entrySet().stream().map(mapToPostDTO)
            .collect(toUnmodifiableList());

是否有一种有效或自动的方法可以直接从存储库中获取POSTDTO项目?

java hibernate jpa spring-data-jpa
1个回答
0
投票

您按标题搜索评论有点奇怪。标题不是唯一的,同一标题可能有10个不同的帖子,因此您将获取所有10个帖子的评论。我建议您按帖子ID搜索评论。

@Repository
public interface PostCommentRepository extends JpaRepository<PostComment, Long> {

    //not entirely sure if that is valid jpql, should work. 
    // Otherwise accept "Long postId", then sql: select review from post_comment where post_id = :postId
    @Query("select c.review from PostComment c where c.post = :post")
    List<String> findAllByPost(Post post);
}

... main() {
   ...
   List<String> reviews = commentRepo.findAllByPost(post);
   PostDTO dto = new PostDTO(post.getTitle(), reviews);
}
© www.soinside.com 2019 - 2024. All rights reserved.