Hibernate关系映射(六)多对多单向关联@ManyToMany Annotation方式

本篇介绍多对多的单向关联,多对多的处理方式是,有一张中间表,中间表保存两个多方之间的关系。首先来看实际应用场景:在之前开发的系统中,应用了基于角色的控制访问,也就是RBAC模型,一个用户可能存在多种角色,一种角色也可能有多个用户,所以用户和角色之间是一个多对多的关系。实体:用户(User),具有如下属性:Id,名称(name),角色列表(roles);实体:角色(Role),具有如下属性:Id,名称(name);既然是单项关联,所以就可以从当前用户,读取到具有的角色列表,而不能从当前角色获取用户列表。


下面来看表结构:
这里写图片描述
中间表user_role中,有一个字段userId作为外键指向了user表的id,同样,有一个字段roleId也是作为外键指向了role表的id,这样就保存了两个多方之间的关系。


下面来看实体类的书写:

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class User {

    private Integer id;
    private String name;
    private Set<Role> roles = new HashSet<Role>();

    public User() {
        super();
    }

    public User(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToMany
    @JoinTable(name="user_role",
            joinColumns={@JoinColumn(name="userId")},
            inverseJoinColumns={@JoinColumn(name="roleId")})
    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

}

用一个Set集合来保存User中的Role列表,@ManyToMany表示这是一个多对多关系@JoinTable用来设置中间表,name=”user_role”中间表的名称,joinColumns={@JoinColumn(name=”userId”)},设置当前实体在中间表中的映射,也就是说在中间表中设置一个字段叫userId,指向当前user表的id;inverseJoinColumns={@JoinColumn(name=”roleId”)}设置对方实体在中间中的映射,也就是说在中间表中设置一个字段roleId,指向对方表(role表)的id。

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Role {

    private Integer id;
    private String name;



    public Role() {
        super();
    }


    public Role(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }


    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }



}

role表就没什么要介绍的了。


下面来看CRUD测试:
首先是添加数据的测试,testCreate()

     @Test
     public void testCreate(){
      Session session = sessionFactory.getCurrentSession();
      session.beginTransaction();

      User u1 = new User();
      u1.setName("admin");

      User u2 = new User();
      u2.setName("wan");

      Role r1 = new Role();
      r1.setName("超级管理员");

      Role r2 = new Role();
      r2.setName("普通用户");

      Set<Role> roleSet1 = new HashSet<Role>();
      roleSet1.add(r1);
      roleSet1.add(r2);

      u1.setRoles(roleSet1);


      Set<Role> roleSet2 = new HashSet<Role>();
      roleSet2.add(r2);

      u2.setRoles(roleSet2);

      session.saveOrUpdate(u1);
      session.saveOrUpdate(u2);
      session.saveOrUpdate(r1);
      session.saveOrUpdate(r2);

      session.getTransaction().commit();
     }

新建一个u1,叫admin,一个u2,叫wan
新建一个r1,叫“超级管理员”,一个r2,叫“普通用户”
new一个角色集合,包含了r1和r2,设置给u1
new一个角色集合,只包含r2,设置给u2
将上述内容,保存到数据库,就是本测试用例。
那么,在数据库中,中间表应该有三条数据
userId roleId
1 1
1 2
2 2
结果如下:
这里写图片描述
这里写图片描述
这里写图片描述


接下来进行读取数据的测试,testRead()

     @Test
     public void testRead(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         User user = (User) session.load(User.class, 1);
         System.out.println(user.getName());
         for (Role r:user.getRoles()){
             System.out.println(r.getName());
         }


         session.getTransaction().commit();
     }

结果如下:

Hibernate: 
    select
        user0_.id as id6_0_,
        user0_.name as name6_0_ 
    from
        User user0_ 
    where
        user0_.id=?
admin
Hibernate: 
    select
        roles0_.userId as userId1_,
        roles0_.roleId as roleId1_,
        role1_.id as id7_0_,
        role1_.name as name7_0_ 
    from
        user_role roles0_ 
    left outer join
        Role role1_ 
            on roles0_.roleId=role1_.id 
    where
        roles0_.userId=?
超级管理员
普通用户

下面是修改操作,testUpdate()

     @Test
     public void testUpdate(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         User user = (User) session.load(User.class, 2);
         user.setName("administrator");

         Role role = (Role) session.load(Role.class, 1);
         Set<Role> roleSet = new HashSet<Role>();
         roleSet.add(role);

         user.setRoles(roleSet);

         session.saveOrUpdate(user);


         session.getTransaction().commit();
     }

将用户为wan读取出来,修改名字为administrator,将普通用户的角色修改为超级管理员,结果如下:
这里写图片描述
这里写图片描述


最后是删除操作,testDelete()

     @Test
     public void testDelete(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         User user = (User) session.load(User.class, 2);
         user.setRoles(null);

         session.delete(user);

         session.getTransaction().commit();
     }

结果:
这里写图片描述
这里写图片描述


下一篇介绍多对多的双向关联,希望对你有所帮助

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值