Hibernate 多對多資料更新範例#

因同學在這方面比較有問題,才有這份文件。

以下是多對多使用 Java 物件實作範例:

情境#

假設這是一個朋友與群組的多對多關係,一個群組可以存多個朋友,朋友也可以屬於多個群組。

SQL Table 設計如下(本範例為 MSSQL 語法)

SQL 關聯圖:

sql relation image

use hibernatedb
GO
create table friends(
friends_id int not null primary key identity(1,1),
friendName nvarchar(50) not null
)
GO
create table groups(
groups_id int not null primary key identity(1,1),
groupName nvarchar(50) not null
)
GO
create table friend_group(
fg_id int not null primary key identity(1,1),
fk_friend_id int not null references friends(friends_id),
fk_group_id int not null references groups(groups_id)
)

Java Bean 設置#

  1. MyGroup.java
@Entity
@Table(name = "groups")
public class MyGroup {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "groups_id")
private Integer gropuId;
@Column(name ="groupName")
private String groupName;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "friend_group", joinColumns = {
@JoinColumn(name = "fk_group_id", referencedColumnName = "groups_id") }, inverseJoinColumns = {
@JoinColumn(name = "fk_friend_id", referencedColumnName = "friends_id") })
private Set<Friend> friends = new HashSet<Friend>();
//.... constructer , getter and setter
  1. Friend.java
@Entity
@Table(name = "friends")
public class Friend {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "friends_id")
private Integer friendId;
@Column(name = "friendName")
private String friendName;
@ManyToMany(mappedBy = "friends")
private Set<MyGroup> groups = new HashSet<MyGroup>();
//.... constructer , getter and setter

範例資料#

輸入一些範例資料

insert into friends (friendName) values ('Tom'),('Mary'),('Tina')
GO
insert into groups (groupName) values('high school'),('game'),('work')
GO
insert into friend_group (fk_friend_id, fk_group_id) values
(1,1),(1,2),(2,3),
(3,1),(3,2),(3,3)
GO

主要目標#

假設 work 群組內原本有 Mary, Tina,今天有新來的同事 Bill 且 Tina 離職只剩 Mary, Bill 需要在工作群組。

動作: 先讓 work 群組只剩 Mary ,然後要把 Bill 加入朋友(Friend Table),且加在 work 群組中。

也就是修改前如圖:

friends before image

然後修改後表格應該要長這樣子:

friends after image

以下為操作 Java 物件的作法

public class DemoManyToManyFriendEx2 {
public static void main(String[] args) {
try {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
MyGroup group3 = session.get(MyGroup.class, 3);
System.out.println("group3.getGroupName()" + group3.getGroupName());
Set<Friend> friends = group3.getFriends();
// 因為有 Lazy Loading 的設置,必須先把 friends 初始化(initialize),才會強制讀取多方物件。
Hibernate.initialize(friends);
System.out.println("----------------------------------");
Iterator<Friend> it = friends.iterator();
System.out.println("friends.iterator();");
System.out.println("friends"+ friends);
// 走訪每個 friends 裡面的成員,並只剩下 Mary
while (it.hasNext()) {
Friend friend = it.next();
String name = friend.getFriendName();
System.out.println("friend.getFriendName();" + name);
if (!name.equals("Mary")) {
System.out.println("in if");
it.remove();
}
}
System.out.println("friends.size();"+friends.size());
// 新增 Bill 為朋友,且加入透過 work 群組拿到的 friends set
Friend aNewFriend = new Friend("Bill");
friends.add(aNewFriend);
System.out.println("friends.size();"+friends.size());
session.getTransaction().commit();
System.out.println("Commit OK!!");
} catch (Exception e) {
System.out.println("Something wrong and Roll Back!!");
e.printStackTrace();
} finally {
HibernateUtil.closeSessionFactory();
}
}
}

成功的 console#

session.beginTransaction();
Hibernate:
select
mygroup0_.groups_id as groups_i1_8_0_,
mygroup0_.groupName as groupnam2_8_0_
from
groups mygroup0_
where
mygroup0_.groups_id=?
group3.getGroupName()work
Hibernate:
select
friends0_.fk_group_id as fk_group1_6_0_,
friends0_.fk_friend_id as fk_frien2_6_0_,
friend1_.friends_id as friends_1_7_1_,
friend1_.friendName as friendna2_7_1_
from
friend_group friends0_
inner join
friends friend1_
on friends0_.fk_friend_id=friend1_.friends_id
where
friends0_.fk_group_id=?
----------------------------------
friends.iterator();
friends[Friend [friendId=2, friendName=Mary], Friend [friendId=3, friendName=Tina]]
friend.getFriendName();Mary
friend.getFriendName();Tina
in if
friends.size();1
friends.size();2
Hibernate:
insert
into
friends
(friendName)
values
(?)
Hibernate:
delete
from
friend_group
where
fk_group_id=?
and fk_friend_id=?
Hibernate:
insert
into
friend_group
(fk_group_id, fk_friend_id)
values
(?, ?)
Commit OK!!

其他作法#

  1. 也可以使用 HQL 方法。
  2. 使用 Hibernate 的 createSQLQuery 物件操作原生的 SQL 語法。