近來(lái),在做的一個(gè)NewsMS項(xiàng)目中,需要用到多對(duì)多關(guān)聯(lián)映射,以下是項(xiàng)目中用到的兩個(gè)實(shí)體類:用戶類User和角色類Role,它們之間是多對(duì)多的關(guān)系。
//用戶表
@Entity
@Table(name="rong_user")

public class User
{

//省略其它內(nèi)容

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
{
//省略其它內(nèi)容

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;
}
}

這兩個(gè)生成數(shù)據(jù)庫(kù)中的三個(gè)表,分別是rong_user, rong_role和一個(gè)中間表rong_user_role。
Hibernate和JPA控制關(guān)聯(lián)關(guān)系的,只能是一方,不能雙方控制的,上面的程序中,我通過(guò)在Role類中設(shè)置mappedBy="roles"來(lái)設(shè)置由User來(lái)控制關(guān)系,
這樣,問(wèn)題就出現(xiàn)了:當(dāng)我在要?jiǎng)h除角色Role時(shí),如果沒(méi)有用戶擁有這個(gè)角色的話,就能成功刪除;如果有用戶擁有這個(gè)角色的時(shí)候,就不能刪除,會(huì)拋以下異常:
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`))
/******堆棧信息略*****/
當(dāng)我設(shè)置成單向關(guān)系映射時(shí),即把Role類中,Set<User>信息去掉,這樣,也不能刪,原因也是說(shuō)有外鍵約束!怎么辦?
苦惱了好幾天,最后,只能歸于Hibernate(JPA)的多對(duì)多關(guān)聯(lián)映射設(shè)計(jì)得有點(diǎn)不符實(shí)際!就像上面我說(shuō)的例子,有人選了某角色,就不能刪掉該角色。還有一種做法是,在Role類中:

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

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