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();
}
結果:
下一篇介紹多對多的雙向關聯,希望對你有所幫助