【问题标题】:I have a problem with "You may also like" feature in Spring boot JPA我对 Spring boot JPA 中的“您可能也喜欢”功能有疑问
【发布时间】:2021-01-15 07:45:47
【问题描述】:

我想为博客创建一个简单的“您可能也喜欢”功能。 有帖子,每个帖子都有一个或多个标签。一个标签也可以包含许多帖子。我想实现你打开一个帖子的功能,并且将具有相似标签的帖子推荐给你。

所以我创建了 3 个实体:

Post.java

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

    @Column
    private String text;

    @Column
    private String author;

    @OneToMany(mappedBy = "post")
    Set<PostTags> postTags;

    public Post(){}

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Set<PostTags> getPostTags() {
        return postTags;
    }

    public void setPostTags(Set<PostTags> postTags) {
        this.postTags = postTags;
    }
}

标签.java

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

    @Column
    private String name;

    @OneToMany(mappedBy = "tag")
    Set<PostTags> postTags;

    public Set<PostTags> getPostTags() {
        return postTags;
    }

    public void setPostTags(Set<PostTags> postTags) {
        this.postTags = postTags;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

PostTags.java

@Entity
public class PostTags {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column
    private Long id;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;

    @ManyToOne
    @JoinColumn(name = "tag_id")
    private Tags tag;

    public PostTags(){}

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Post getPost() {
        return post;
    }

    public void setPost(Post post) {
        this.post = post;
    }

    public Tags getTag() {
        return tag;
    }

    public void setTag(Tags tag) {
        this.tag = tag;
    }
}

和存储库:

@Repository
public interface PostTagsRepository extends JpaRepository<PostTags, Long> {
    @Query("select p.post from PostTags p where p.tag.id IN :tagIds")
    Set<Post> findPostsbyTagIds (List<Long> tagIds);
}


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

    @Query("select p from Post p where p.author = :author")
    Set<Post> findPostsByAuthor(String author);
}

我设法以业余的方式创建了此功能,但总比没有好。我把所有东西都用一种方法堆积起来只是为了测试它:

 @GetMapping("/posts")
    public Set<Post> showRecommendedPosts(){

        //Imitate post id
        long postId = 1;
        Post postFound = postRepository.findById(postId).get();
        Set<PostTags> postTags = postFound.getPostTags();

        List<Long> listTagIds = new ArrayList<>();

        //extract ids of the tags from the post
        for(PostTags tag : postTags){
            listTagIds.add(tag.getTag().getId());
        }

        //find posts by Author
        Set<Post> postsByAuthor = postRepository.findPostsByAuthor(postFound.getAuthor());

        //find posts by Tags
        Set<Post> postsByTagIds = postTagsRepository.findPostsbyTagIds(listTagIds);

        //We combine both sets
        Set<Post> recommendedPosts = new HashSet<>(postsByAuthor);
        recommendedPosts.addAll(postsByTagIds);
        recommendedPosts.remove(postFound);

        return recommendedPosts;
    }

但这只有在我像这样手动将数据添加到数据库中的“post_tags”表时才有效:

这是我的问题,我不知道如何在 Spring 中为帖子添加多个标签。因为它会是这样的:

 PostTags newPostTag1 = new PostTags();
        newPostTag.setPost(post1);
        newPostTag.setTag(tag1);

        PostTags newPostTag2 = new PostTags();
        newPostTag2.setPost(post1);
        newPostTag2.setTag(tag2);

        PostTags newPostTag3 = new PostTags();
        newPostTag3.setPost(post1);
        newPostTag3.setTag(tag3);

等等…… 因此,这不是一个选择。那么如何正确保存标签?还是我的实体创建不正确?我的错误是什么?谢谢!

【问题讨论】:

    标签: spring-boot hibernate jpa


    【解决方案1】:

    我不确定Tag 是一个实体背后的想法。

    我怎么看是您使用postTags 并将其更改为tags。如果您想以其他方式限制用户或一组字符串,则此 tags 将是一组枚举。之后,我将添加一个端点,该端点根据您的You may also like 功能的标签或标签列表返回帖子。该端点只是向数据库发出请求(查找标签包含 givenTag max 10 的帖子)。最后,您只有一个实体:

    @Entity
    @Table
    public class Post {
        @Id
        @Column
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column
        private String text;
    
        @Column
        private String author;
    
        @Column
        @Convert(converter = StringListConverter.class)
        Set<String> tags;
    
        // ...
    }
    

    转换器实现here

    【讨论】:

    • 感谢您的帮助。但是你能再给我一个提示吗?要按标签选择帖子,我必须使用本机查询,因为我未能正确编写 jpql 查询。所以这个查询有效: @Query(value = "SELECT * FROM post WHERE tags LIKE %:tag% OR author LIKE %:author%" , nativeQuery = true) Set findPostsByTagsAndAuthor(String tag, String author );
    • 那么如何在 jpql 中编写它,因为我尝试了这个:Query("select p from Post p where :tag in(p.tags)") 并且它不起作用,因为它需要 p。标签不是一个集合。如果你帮助我,我会很高兴!谢谢
    • 这里的问题是p.tags 只是一个字符串而不是子查询。这就是in 不起作用的原因。如果你真的想使用in,我刚刚发现@ElementCollection 可以工作。基本上,它会创建另一个表来存储列表。这样你就可以在in 后面创建一个连接表。 stackoverflow.com/questions/287201/…
    • 谢谢你的回复,我也试过这个选项,它会创建另一个表,所以它不适合我。所以我决定坚持使用原生查询
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 2018-06-26
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    相关资源
    最近更新 更多