【问题标题】:@ManyToMany Relationship Between Three Tables三个表之间的@ManyToMany 关系
【发布时间】:2017-07-18 05:34:19
【问题描述】:

我的 Spring JPA 应用程序中有三个独立的实体 - 用户、部门、角色

我的数据库中有一个连接表来关联这些实体中的每一个:USER_DEPARTMENT_ROLE

我的问题是,如何在我的实体类中定义这种关系?我是否必须在每个单独的实体中定义 @ManyToMany 关系?我知道如何定义两个表之间的这种关系,但是对于两个以上的表我不知道从哪里开始。

感谢任何帮助!

【问题讨论】:

    标签: java spring jpa orm


    【解决方案1】:

    如果您的联接表中映射了两个以上的关系,那么我建议创建一个单独的实体,用于映射该特定表。

    问题是您是否可以有一个不同的 id 列作为人工主键,或者您必须坚持使用由三个外键构建的复合主键。

    如果您可以添加人工 id(这是设计数据库的现代方式),那么您的映射应该如下所示:

    选项 1

    class User {
        @OneToMany(mappedBy = "user", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    
    class Department{
        @OneToMany(mappedBy = "department", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    
    class Role{
        @OneToMany(mappedBy = "role", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    
    class UserDepartmentRoleLink {
    
        @Id
        @GeneratedValue
        private Long id;
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "user_id")
        private User user;
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "department_id")
        private Department department;
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "role_id")
        private Role role;
    
    }
    

    关于为多对多关系设置级联类型是棘手的,对于涉及三个表的多对多来说甚至更棘手,因为每个实体都可以根据情况扮演父母或孩子的角色。我建议只坚持cascade = {CascadeType.PERSIST, CascadeType.MERGE} 并手动处理其他操作。

    如果您必须保留复合主键,那么您应该添加额外的 Id 类并将链接实体更改为以下内容:

    选项 2

    class User {
        @OneToMany(mappedBy = "linkPk.user", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    
    class Department{
        @OneToMany(mappedBy = "linkPk.department", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    
    class Role{
        @OneToMany(mappedBy = "linkPk.role", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        private Set<UserDepartmentRoleLink> userDepartmentRoleLinks;
    }
    

    联动表

    class UserDepartmentRoleLink {
    
        @EmbeddedId
        private UserDepartmentRoleLinkId linkPk 
              = new UserDepartmentRoleLinkId(); 
    
        @Transient
        public User getUser() {
            return getLinkPk().getUser();
        }
    
        @Transient
        public User getDepartment() {
            return getLinkPk().getDepartment();
        }
    
        @Transient
        public User getRole() {
            return getLinkPk().getRole();
        }    
     }
    
    @Embeddable
    public class UserDepartmentRoleLinkId implements java.io.Serializable {
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "user_id")
        private User user;
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "department_id")
        private Department department;
    
        @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "role_id")
        private Role role;
    

    最重要的是,您可以在此处使用多对多,如本文所述 -> example。但在我看来,如果你像上面那样映射链接表,你会省去很多麻烦。最后,电话是你的..

    【讨论】:

    • 选项 1 恕我直言是最简单和最干净的选项。感谢@Maciej 的出色回答。另外我想知道为什么这没有标记为“已接受”?
    • @Maciej Kowalski - 我们如何在此处应用复合键以确保将唯一组合保存在数据库中?
    • @Maciej - 请您在这里指导我:stackoverflow.com/questions/57311851/…
    • @maciej 对于很多人来说这个解决方案不起作用!
    猜你喜欢
    • 1970-01-01
    • 2012-07-11
    • 2013-07-01
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多