JPA(六)多对多

1.多对多实体类配置

@Entity
@Table(name = "role")
public class Role {

    @Id
    @Column(name = "role_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long roleId;

    @Column(name = "role_name")
    private String roleName;

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "rid",referencedColumnName="role_id")}, 
                            inverseJoinColumns = {@JoinColumn(name = "uid",referencedColumnName="user_id")})
    private Set userList = new HashSet<>();
}   
@Entity
@Table(name = "users")
public class Users {

    @Id
    @Column(name = "user_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;
    @Column(name = "user_name")
    private String userName;
    @Column(name = "user_address")
    private String address;
    @Column(name = "user_gender")
    private String gender;

    @ManyToMany(cascade=CascadeType.ALL,mappedBy="userList")
    private Set roles = new HashSet<>(0);
}

2、注解说明

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

  • @JoinTable
    作用:
    针对中间表的配置
    属性:
      nam:配置中间表的名称
      joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
      inverseJoinColumn:中间表的外键字段关联对方表的主键字段
    - @JoinColumn
    作用:
      用于定义主键字段和外键字段的对应关系。
    属性:
      name:指定外键字段的名称
      referencedColumnName:指定引用主表的主键字段名称
      unique:是否唯一。默认值不唯一
      nullable:是否允许为空。默认值允许。
      insertable:是否允许插入。默认值允许。
      updatable:是否允许更新。默认值允许。
      columnDefinition:列的定义信息。

3测试

3.1、保存

    /**
     * 
     * 1、保存一个实体
     */
    @Test
    public void testAdd() {
        // 定义对象
        Role role1 = new Role();
        Role role2 = new Role();
        Users users1 = new Users();
        Users users2 = new Users();


        role1.setRoleName("角色1");
        role1.getUserList().add(users1);
        role1.getUserList().add(users2);

        role2.setRoleName("角色2");
        role2.getUserList().add(users2);

        users1.setAddress("北京");
        users1.setGender("男");
        users1.setUserName("张三");
        users1.getRoles().add(role1);

        users2.setAddress("上海");
        users2.setGender("女");
        users2.setUserName("赵四");
        users2.getRoles().add(role1);
        users2.getRoles().add(role2);

        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            // 获取实体管理对象
            em = JpaUtil.getEntityManager();
            // 获取事务对象
            tx = em.getTransaction();
            // 开启事务
            tx.begin();
            // 执行操作

            em.persist(role1);

            // 提交事务
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的 2
个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即
可,推荐在被动的一方放弃,配置如下:
@ManyToMany(mappedBy="roles")
private Set users = new HashSet(0);

3.2删除

     /**
        * 删除操作
        * 删除从表数据:可以随时任意删除。
        * 删除主表数据:
        * 有从表数据引用
        * 1、不能删除
        * 2、如果还想删除,使用级联删除
        * 没有从表数据引用:随便删
        *
        * 在实际开发中,级联删除请慎用!(在一对多的情况下)
        */
    @Test
    public void testRemove() {
        // 定义对象
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            // 获取实体管理对象
            em = JpaUtil.getEntityManager();
            // 获取事务对象
            tx = em.getTransaction();
            // 开启事务
            tx.begin();
            // 执行操作
            Users u = em.find(Users.class, 2L);

            em.remove(u);
            // 提交事务
            tx.commit();

        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
级联删除的配置:
@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.AL
L) //用 CascadeType.REMOVE 也可以
private Set linkmans = new HashSet(0);

你可能感兴趣的:(JPA)