近來,在做的一個NewsMS項目中,需要用到多對多關聯映射,以下是項目中用到的兩個實體類:用戶類User和角色類Role,它們之間是多對多的關系。
//用戶表
@Entity
@Table(name="rong_user")

public class User
{

//省略其它內容

private Set<Role> roles = new LinkedHashSet<Role>(); //角色集合

@ManyToMany(cascade =
{CascadeType.PERSIST, CascadeType.MERGE})

@JoinTable(name = "rong_user_role", joinColumns =
{ @JoinColumn(name ="user_id" )}, inverseJoinColumns =
{ @JoinColumn(name = "role_id") })
@OrderBy("id")

public Set<Role> getRoles()
{
return roles;
}

public void setRoles(Set<Role> roles)
{
this.roles = roles;
}
}
//角色表
@Entity
@Table(name="rong_role")

public class Role
{
//省略其它內容

private Set<User> user = new LinkedHashSet<User>(); //用戶集合


@ManyToMany(cascade =
{CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "roles", fetch = FetchType.LAZY)

public Set<User> getUser()
{
return user;
}

public void setUser(Set<User> user)
{
this.user = user;
}
}

這兩個生成數據庫中的三個表,分別是rong_user, rong_role和一個中間表rong_user_role。
Hibernate和JPA控制關聯關系的,只能是一方,不能雙方控制的,上面的程序中,我通過在Role類中設置mappedBy="roles"來設置由User來控制關系,
這樣,問題就出現了:當我在要刪除角色Role時,如果沒有用戶擁有這個角色的話,就能成功刪除;如果有用戶擁有這個角色的時候,就不能刪除,會拋以下異常:
12:53:33,125 WARN JDBCExceptionReporter:100 - SQL Error: 1451, SQLState: 23000
12:53:33,125 ERROR JDBCExceptionReporter:101 - Cannot delete or update a parent row: a foreign key constraint fails (`newsms/rong_user_role`, CONSTRAINT `FKF1698421A337A5FA` FOREIGN KEY (`role_id`) REFERENCES `rong_role` (`id`))
12:53:33,171 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
/****堆棧信息略****/

Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`newsms/rong_user_role`, CONSTRAINT `FKF1698421A337A5FA` FOREIGN KEY (`role_id`) REFERENCES `rong_role` (`id`))
/******堆棧信息略*****/
當我設置成單向關系映射時,即把Role類中,Set<User>信息去掉,這樣,也不能刪,原因也是說有外鍵約束!怎么辦?
苦惱了好幾天,最后,只能歸于Hibernate(JPA)的多對多關聯映射設計得有點不符實際!就像上面我說的例子,有人選了某角色,就不能刪掉該角色。還有一種做法是,在Role類中:

@ManyToMany(cascade =
{CascadeType.PERSIST, CascadeType.MERGE,CascadeType.REMOVE}, mappedBy = "roles", fetch = FetchType.LAZY)

public Set<User> getUser()
{
return user;
}
即加多一個“CascadeType.REMOVE”,這樣能把角色Role給刪掉了,但連擁有該角色的所有用戶User也被級聯刪掉了。這樣來看,某個用戶擁有許多角色,就因為其中有這一個角色,就被級聯刪了整個自己,那不是很冤枉。這也不符合實際!
個人認為,Hibernate(JPA)在設置多對多關聯映射時,應該有做法能使得雙方都能控制關聯關系才好,才符合實際吧!但事實上,好像還沒有發現有Hibernate(JPA)這種能力!
本文原創,轉載請注明出處,謝謝!http://www.tkk7.com/rongxh7(心夢帆影JavaEE技術博客)
posted on 2009-06-08 13:33
心夢帆影 閱讀(26943)
評論(15) 編輯 收藏 所屬分類:
Hibernate 、
JPA