24 表之间关系之多对多

多对多的表关系建立靠的是中间表,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多

一个用户可以具有多个角色,所以在用户实体类中应该包含多个角色的信息,代码如下:

/**
 * 用户的数据模型
 */
@Entity
@Table(name="sys_user")
@Data
public class SysUser implements Serializable {
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long userId;
    @Column(name="user_code")
    private String userCode;
    @Column(name="user_name")
    private String userName;
    @Column(name="user_password")
    private String userPassword;
    @Column(name="user_state")
    private String userState;
    
    //多对多关系映射
    @ManyToMany(mappedBy="users")
    private Set<SysRole> roles = new HashSet<SysRole>(0);
}

一个角色可以赋予多个用户,所以在角色实体类中应该包含多个用户的信息

/**
 * 角色的数据模型
 */
@Entity
@Table(name="sys_role")
@Data
public class SysRole implements Serializable {
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="role_id")
    private Long roleId;
    @Column(name="role_name")
    private String roleName;
    @Column(name="role_memo")
    private String roleMemo;
    
    //多对多关系映射
    @ManyToMany
    @JoinTable(name="user_role_rel",//中间表的名称
              //中间表user_role_rel字段关联sys_role表的主键字段role_id
              joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},
              //中间表user_role_rel的字段关联sys_user表的主键user_id
              inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}
    )
    private Set<SysUser> users = new HashSet<SysUser>(0);
}

映射的注解说明

@ManyToMany
    作用:用于映射多对多关系
    属性:
        cascade:配置级联操作。
        fetch:配置是否采用延迟加载。
        targetEntity:配置目标的实体类。映射多对多的时候不用写。

@JoinTable
    作用:针对中间表的配置
    属性:
        nam:配置中间表的名称
        joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段                          
        inverseJoinColumn:中间表的外键字段关联对方表的主键字段
        
@JoinColumn
    作用:用于定义主键字段和外键字段的对应关系。
    属性:
        name:指定外键字段的名称
        referencedColumnName:指定引用主表的主键字段名称
        unique:是否唯一。默认值不唯一
        nullable:是否允许为空。默认值允许。
        insertable:是否允许插入。默认值允许。
        updatable:是否允许更新。默认值允许。
        columnDefinition:列的定义信息。
    @Autowired
    private UserDao userDao;
    
    @Autowired
    private RoleDao roleDao;
    /**
     * 需求:
     *     保存用户和角色
     * 要求:
     *     创建2个用户和3个角色
     *     让1号用户具有1号和2号角色(双向的)
     *     让2号用户具有2号和3号角色(双向的)
     *  保存用户和角色
     * 问题:
     *  在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
     * 解决办法:
     *     让任意一方放弃维护关联关系的权利
     */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void save(){
        //创建对象
        SysUser u1 = new SysUser();
        u1.setUserName("用户1");
        SysRole r1 = new SysRole();
        r1.setRoleName("角色1");
        //建立关联关系
        u1.getRoles().add(r1);
        r1.getUsers().add(u1);
        //保存
        roleDao.save(r1);
        userDao.save(u1);
    }

在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:

//放弃对中间表的维护权,解决保存中主键冲突的问题
    @ManyToMany(mappedBy="roles")
    private Set<SysUser> users = new HashSet<SysUser>(0);

删除操作

@Autowired
    private UserDao userDao;
    /**
     * 删除操作
     *     在多对多的删除时,双向级联删除根本不能配置
     * 禁用
     *    如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
     */
    @Test
    @Transactional
    @Rollback(false)//设置为不回滚
    public void testDelete() {
        userDao.delete(1l);
    }

 

  

posted @ 2019-12-31 23:33  zhaochengf  阅读(429)  评论(0编辑  收藏  举报