【问题标题】:JPA ManToMany association and insert, retrieve data with Spring Data RepositoryJPA ManToMany 关联并使用 Spring Data Repository 插入、检索数据
【发布时间】:2021-05-20 03:41:03
【问题描述】:

我需要在 2 个实体(即项目和文章)之间设置多对多关系。 用例是一个可以链接到许多相关文章的项目。每篇文章都会链接到各种项目。 我在我的项目中使用 Spring 数据存储库,并且无法持久保存和检索与项目和文章的这种关系。

@Entity @Table(name = "projects")
@Getter @Setter
public class Project {
    @Id
    String id;
    String name;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "project_articles",
        joinColumns = { @JoinColumn(name = "project_id", referencedColumnName = "id") },
        inverseJoinColumns = { @JoinColumn(name = "article_id", referencedColumnName = "id") })
    private List<Article> articles = new ArrayList<>();

    public Project addArticle(Article p) {
        if (articles == null) articles = new ArrayList<>();
        p.getProjects().add(this);
        articles.add(p);
        return this;
    }
}

文章实体

@Entity @Table(name = "articles")
@Getter @Setter
public class Article {

    @Id
    String id;
    String title;
    String author;
    String body;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "project_articles")
    List<Project> projects = new ArrayList<>();

}

ProjectArticles 连接表实体。我创建它是为了解决休眠中的表创建问题。

@Entity(name = "ProjectArticles")
@Table(name = "project_articles")
@AssociationOverrides({
    @AssociationOverride(name = "key.project", joinColumns = @JoinColumn(name = "project_id")),
    @AssociationOverride(name = "key.article", joinColumns = @JoinColumn(name = "article_id")) }
)
@Getter @Setter
public class ProjectArticles {
    @EmbeddedId ProjectArticleId key;

    @Embeddable @Getter @Setter
    public static class ProjectArticleId {
        @Column(name = "project_id", columnDefinition = "varchar(255)")
        ProjectEntity project;

        @Column(name = "article_id", columnDefinition = "varchar(255)")
        Article article;
    }
}

这里是 spring 数据存储库。

public interface ProjectRepository extends JpaRepository<Project, String> {
    public Project findProjectByName(String name);
    public List<Project> findProjectByArticle(String articleId);
}

public interface ArticleRepository extends JpaRepository<Article, String> {
    public List<Article> findArticlesByTitle(String title);

    // NOTE: Does not work
    @Query("SELECT a from Article a JOIN FETCH a.projects LEFT JOIN ProjectEntity p ON p.id = :project")
    public List<Article> findArticlesByProject(@Param("project") String project);

    @Query("SELECT a from Article a LEFT JOIN ProjectEntity p ON p.id = :project")
    public List<Article> findArticleByProject(ProjectEntity project);
}

理想情况下,我想在服务中使用 repo,如下所示。

Article ar1 = articleRepository.save(new Article("Article title", "Author 1"));
Article ar2 = articleRepository.save(new Article("Article title 2", "Author 2"));
Article ar3 = articleRepository.save(new Article("Article title 3", "Author 3"));

Project pr1 = projectRepository.save(new Project("Project name 1"));
Project pr2 = projectRepository.save(new Project("Project name 2"));
Project pr3 = projectRepository.save(new Project("Project name 3"));

pr1.addArticle(ar1);
pr1.addArticle(ar2);
pr2.addArticle(ar1);
pr2.addArticle(ar2);

ar3.addProject(pr3);
ar3.addProject(pr1);
ar3.addProject(pr2);

articleRepository.findArticlesByProject("project-2-id");
projectRepository.findProjectByArticle("article-3-id");

但事情不工作。当我将现有文章添加到项目并保存(更新)它时,在关系表(“project_articles”)中尝试输入新行但没有项目 ID,并且出现异常。

我在这里做错了什么?我设计实体的方式有可能吗?

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa many-to-many


    【解决方案1】:

    CascadeType.PERSIST(你使用的CascadeType.ALL涉及)的主要思想是创建实体实例,设置必要的双边关系(Project -> ArticlesArticle ->项目),然后才保存到数据库。如果您保存所有项目,那么由于CascadeType.PERSIST 和实体关系,文章会被隐式保存

    试试这个

    @Transactional
    public void save() {
        Article ar1 = new Article("Article title", "Author 1");
        Article ar2 = new Article("Article title 2", "Author 2");
        Article ar3 = new Article("Article title 3", "Author 3");
    
        Project pr1 = new Project("Project name 1");
        Project pr2 = new Project("Project name 2");
        Project pr3 = new Project("Project name 3");
    
        pr1.addArticle(ar1);
        pr1.addArticle(ar2);
        pr1.addArticle(ar3);
    
        pr2.addArticle(ar1);
        pr2.addArticle(ar2);
        pr2.addArticle(ar3);
    
        pr3.addArticle(ar3);
    
        projectRepository.saveAll(Arrays.asList(pr1, pr2, pr3));
    }
    

    【讨论】:

    • 检查我的答案。我想我明白你想说什么,但你的解决方案不完整。感谢您的回复。
    • 我已经为答案添加了解释
    【解决方案2】:

    我已按照几篇博文中描述的指南解决了这种情况。

    另外,我需要解决 JSON 序列化无限递归问题。

    这是最终的 JPA 模型。

    @Entity @Table(name = "projects")
    @Getter @Setter
    public class Project {
        @Id
        String id;
        String name;
    
        @JsonIgnoreProperties("projects")
        @ManyToMany(cascade = { PERSIST, MERGE, DETACH, REFRESH }, fetch = FetchType.LAZY)
        @JoinTable(name = "project_articles",
            joinColumns = { @JoinColumn(name = "project_id", referencedColumnName = "id") },
            inverseJoinColumns = { @JoinColumn(name = "article_id", referencedColumnName = "id") })
        private Set<Article> articles = new HashSet<>();
    
        public Project addArticle(Article art) {
            articles.add(art);
            art.getProjects().add(this);
            return this;
        }
    }
    

    更新了文章实体。

    @Entity @Table(name = "articles")
    @Getter @Setter
    public class Article {
    
        @Id
        String id;
        String title;
        String author;
        String body;
    
        @JsonIgnoreProperties("articles")
        @ManyToMany(mappedBy = "articles", cascade = { PERSIST, MERGE, DETACH, REFRESH }, fetch = FetchType.LAZY)
        Set<Project> projects = new HashSet<>();
    
        public Article addProject(Project prj) {
            projects.add(prj);
            prj.getArticles().add(this);
            return this;
        }    
    }
    

    解决了实体保存/更新问题。

    Article ar1 = articleRepository.save(new Article("Article title", "Author 1"));
    Article ar2 = articleRepository.save(new Article("Article title 2", "Author 2"));
    Article ar3 = articleRepository.save(new Article("Article title 3", "Author 3"));
    
    Project pr1 = projectRepository.save(new Project("Project name 1"));
    Project pr2 = projectRepository.save(new Project("Project name 2"));
    Project pr3 = projectRepository.save(new Project("Project name 3"));
    
    /* Link articles 1 and 3 to project 1 */
    pr1.getArticles().add(ar1);
    pr1.getArticles().add(ar3);
    ar1.getProjects().add(pr1);
    ar3.getProjects().add(pr1);
    
    /* Link articles 2 and 3 to project 2 */
    pr2.addArticle(ar3);
    pr2.addArticle(ar2);
    
    /* Link project 3 to article 3 */
    ar3.addProject(pr3);
    

    但尚未解决数据获取问题。例如获取链接到一个项目的所有项目。 (待办事项

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-23
      • 2014-08-31
      • 2017-01-13
      • 1970-01-01
      相关资源
      最近更新 更多