JPA - 双向多对多映射

背景:

    使用SpringData + JPA。在权限管理设计表格的时候,要使用双向多对多,但是碰到了很多问题,此篇博客记录一下我的心得。

    我对权限管理设计的是一个role表,一个permission表,然后在对表与表之间进行多对多双向关联。

    在双向多对多关系中,必须在两表之间指定一个关系维护端,可以通过@ManyToMany中的mappedby来指定关系维护端。

   
这样解释mappedBy:

在哪个model中的某个注解使用了mappedBy,则该model放弃维持关联关系;如上所示,这里为Category放弃维持关联关系,以Item为主;
在哪个属性上面的注解使用了mappedBy属性,则该注解标注的属性的实体类维持关联关系。在我的例子中,以permission表为主。

避免要踩的坑:

  • 要么就在属性上注解,要么就在属性的get方法上添加注解,一定不能同时在两个上添加注解。
  • 在permission表的 @JoinTable中:

 @JoinTable(
            name = "permission_role",
            joinColumns = {@JoinColumn(name = "permission_id", referencedColumnName = "permission_id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")}
    )

name:生成的中间表的名称;

joinColums:映射当前类所在的表在中间表的外键

                   name:当前类所在的表在中间表的外键名称

                   referencedColumnName:映射当前类的属性的名称

inverseJoinColumns:映射关联类所在中间表的外键

  • 双向多对多要配置懒加载策略,否则在最后测试的时候还会报错。如:
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)

以下是role表代码:

package com.wenlot.wenlot.pojo;

import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @author : 许兵
 * @time : 2019-03-11 19:46:34
 * @E-mail : troubleme@aliyun.com
 * @Wechat :玖弦与柒墨
 * @describe :角色表
 */
@Entity
@Getter
@Setter
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
@Table(name = "role")
public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_id", length = 16)
    private Integer id;

    /** 角色名称 */
    @Column(name = "role_name", length = 32)
    private String name;

    /** 该条记录的创建时间 */
    @CreatedDate
    @Column(name = "create_time")
    private Date createTime;

    /** 该条记录的最近更新时间 */
    @LastModifiedDate
    @Column(name = "update_time")
    private Date updateTime;

    @ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Permission> permissions = new HashSet<>();

}

以下是permission表:

package com.wenlot.wenlot.pojo;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @author : 许兵
 * @time : 2019-03-11 19:51:57
 * @E-mail : troubleme@aliyun.com
 * @Wechat :玖弦与柒墨
 * @describe :
 */
@Entity
//@ToString
@Table(name = "permission")
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
public class Permission {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "permission_id")
    private Integer id;

    @Column(name = "permission_name")
    private String name;

    /** 该条记录的创建时间 */
    @CreatedDate
    @Column(name = "create_time")
    private Date createTime;

    /** 该条记录的最近更新时间 */
    @LastModifiedDate
    @Column(name = "update_time")
    private Date updateTime;

    @JoinTable(
            name = "permission_role",
            joinColumns = {@JoinColumn(name = "permission_id", referencedColumnName = "permission_id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")}
    )
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Role> roles = new HashSet<>();

}

测试代码:

 @Test
    public void testSave() {

        Role role = new Role();
        role.setName("管理员");

        Role role1 = new Role();
        role1.setName("部门经理");

        Permission permission = new Permission();
        permission.setName("上传照片");

        Permission permission1 = new Permission();
        permission1.setName("删除照片");

        permission.getRoles().add(role);
        permission.getRoles().add(role1);

        permission1.getRoles().add(role);
        permission1.getRoles().add(role1);

        role.getPermissions().add(permission);
        role.getPermissions().add(permission1);

        role1.getPermissions().add(permission);
        role1.getPermissions().add(permission1);

        permissionRepository.save(permission);
        permissionRepository.save(permission1);

        roleRepository.save(role);
        roleRepository.save(role1);

    }

运行结果的截图:

我的语言能力较弱,若实在没讲清楚还请见谅,大家可以参考这一个博客:

https://blog.csdn.net/J080624/article/details/78776560 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值