1. Inverse
inverse代表是否由己方维护关系。
inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效
(因为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。
inverse特别是用于双向关系,在单向关系中我们并不需要
(单向one-to-many关联关系中,不可以设置inverse="true",因为被控方的映射文件中没有主控方的信息)。
inverse只存在于集合标记的元素中 。Hibernate提供的集合元素包括<set/> <map/> <list/> <array /> <bag />
Inverse属性的作用是:是否将对集合对象的修改反映到数据库中。
inverse属性的默认值为false,表示对集合对象的修改会被反映到数据库中;inverse=false 的为主动方,由主动方负责维护关联关系。
inverse=”true” 表示对集合对象的修改不会被反映到数据库中。
2. Cascade
Cascade代表是否执行级联操作。
cascade决定是否把对对象的改动反映到数据库中,所以cascade对所有的关联关系都起作用(因为关联关系就是指对象之间的关联关系)。
Cascade属性的可能值有
all: 所有情况下均进行关联操作,即save-update和delete。
none: 所有情况下均不进行关联操作。这是默认值。
save-update: 在执行save/update/saveOrUpdate时进行关联操作。
delete: 在执行delete 时进行关联操作。
all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,Student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。
3. 一对多的例子:
有两个类,Father和Child,是一对多的关系。下面这段hbm配置是从Father.hbm.xml中摘取的。
<set name="children" lazy="true" cascade="all" inverse="true"> <key column="fatherid"/> <one-to-many class="my.home.Child"/> </set>
我们知道cascade和inverse的值对会有四种组合的可能(在此仅先假定cascade值为none或all)。
有如下一段代码:
FatherDao fatherDao = new FatherDao(); Father father = new Father("David"); Child child1 = new Child("David Junior One"); Child child2 = new Child("David Junior Two"); father.add(child1); father.add(child2); fatherDao.save(father);
1. 如果cascade="all"且inverse="false"时:
此时可以看到log里面:
// 执行对father的插入 Hibernate: insert into father (name) values (?) // cascade = 'all',所以进行级联操作 Hibernate: insert into child (name, fatherid) values (?, ?) Hibernate: insert into child (name, fatherid) values (?, ?) // inverse = 'false',由father来维护关系(可以看到这些操作是多余的) Hibernate: update child set fatherid =? where ID=? Hibernate: update child set fatherid =? where ID=?
2. 如果cascade = "none" 且 inverse = "false":
// 执行对father的插入 Hibernate: insert into father (name) values (?) // inverse='false',所以更新关系 Hibernate: update child set fatherid =? where ID=? // 但由于cascade='none',child并未插入数据库,导致如下exception org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance
3. 如果cascade = "all" 且 inverse = "true"
// 执行对father的插入 Hibernate: insert into father (name) values (?) // cascade='all',执行对child的插入 Hibernate: insert into child (name, fatherid) values (?, ?) Hibernate: insert into child (name, fatherid) values (?, ?) // 但由于inverse='true',所以未有对关系的维护。但由于一对多的关系中,关系本身在“多”方的表中。所以,无需更新关系。
4. 如果cascade = "none" 且 inverse = "true"
// 只执行对father的插入 Hibernate: insert into father (name) values (?)
可以看到,对于一对多关系,关系应由“多”方来维护(指定“一”方的inverse为true),并且应在“一”方指定相应的级联操作。
4. 多对多:
在多对多关系中,inverse可以为任何一方,没有什么区别。
解疑:
为什么在多对多中不能由双方都来维护关系了:因为这样会导致重复更新中间表的可能,报出重复值的错误。
那么如何在多对多的双向关联中使双方都能维护关系:最好让控制关系的那方来更新关系,如果想让另一方也来维护关系,那么只有在操作这一方的数据时“显式”更新中间表了吧。
注意:
同时注意在双向关联中,对象之间的关联跟上面提及的关系表维护没有关系。一个是对象/java层面的,一个是hibernate数据库层面的。如果你想在更新一方时,也更新另一方的对象集合,请看下面这段代码:
这是Person类中的一段代码,Person和Event是多对多的双向关联关系,他们在对方类中的集合分别为participants和events。关系表由Person维护,所以对象关系的维护也在Person类中,而不是Event类中。
public void addToEvent(Event event) { this.getEvents().add(event); event.getParticipants().add(this); } public void removeFromEvent(Event event) { this.getEvents().remove(event); event.getParticipants().remove(this); }
参考:点击打开