cascade和inverse

Cascade与inverse这两个属性都用于一对多或者多对多的关系中。而inverse特别是用于双向关联关系,在单向关联关系中我们并不需要。

cascade代表是否执行级联操作,inverse代表是否由己方维护关系。

cascade:
cascade的属性有:
1·all:所有操作情况下都进行级联操作,即save-update和delete
2·none:所有情况下均不进行级联操作。这是默认值。
3·save-update:执行save/update/saveOrUpdate时进行级联操作。
4·delete:在执行delete操作的时候进行级联操作。
5·all-delete-orphan:当一个对象节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。


Inverse:

inverse属性值true或者false,默认值false(即默认己方维护关联关系)

false:代表有己方来维护关系,true代表由对方来维护关联关系。
在一个关系中,只能有一方来维护关系,否则会出问题;同时也必须有一方维护关系,否则会出现双方互相推卸责任,谁也不管。

domain对象:
import java.util.HashSet;
import java.util.Set;

public class Father {

private Integer id;
private String name;
private Set<Child> children = new HashSet<Child>();

public Father(){}

public Father(String name){
this.name = name;
}

public void addChild(Child child){
if (!this.children.contains(child)) {
this.children.add(child);
}
}


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;
}
public Set<Child> getChildren() {
return children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}



}


public class Child {

private Integer id;
private String name;
private Father father;

public Child(){}

public Child(String name){
this.name = name;
}

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;
}
public Father getFather() {
return father;
}
public void setFather(Father father) {
this.father = father;
}


}


映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate.domain.inversecascade">

<class name="Father" table="father">
<id name="id" unsaved-value="-1">
<generator class="native" />
</id>
<property name="name"/>
<!-- cascade="all"且inverse="false" -->
<set name="children" cascade="all" inverse="false">
<key column="fatherid"/>
<one-to-many class="Child"/>
</set>

</class>
</hibernate-mapping>



<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate.domain.inversecascade">

<class name="Child" table="child">
<id name="id" unsaved-value="-1">
<generator class="native" />
</id>
<property name="name"/>
<many-to-one name="father" column="fatherid"/>
</class>
</hibernate-mapping>



如果cascade取值分为 all 和 none ; inverse取值分为 false 和 true,这两种情况,那么应该有四种组合。
cascade = all,inverse = false
cascade = all,inverse = true
cascade = none,inverse = false
cascade = none,inverse = true

下面分别测试:

1·cascade = all,inverse = false


测试代码:
	public static void main(String[] args) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();

Father father = new Father("father");
Child child1 = new Child("child 1");
Child child2 = new Child("child 2");

father.addChild(child1);
father.addChild(child2);

session.save(father);

tx.commit();
session.close();

}


执行的sql语句:

Hibernate: insert into father (name) values (?)
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: update child set fatherid=? where id=?
Hibernate: update child set fatherid=? where id=?



2· cascade = all,inverse = true

		<!-- cascade="all"且inverse="true" -->
<set name="children" cascade="all" inverse="true">
<key column="fatherid"/>
<one-to-many class="Child"/>
</set>



执行的sql语句:
Hibernate: insert into father (name) values (?)
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: insert into child (name, fatherid) values (?, ?)


也就是说Child的对象的外键为空了!!

当然此时如果测试代码改成如下方式:

	public static void main(String[] args) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();

Father father = new Father("father");
Child child1 = new Child("child 1");
child1.setFather(father);
Child child2 = new Child("child 2");
child2.setFather(father);

father.addChild(child1);
father.addChild(child2);

session.save(father);

tx.commit();
session.close();

}


执行的sql语句为

Hibernate: insert into father (name) values (?)
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: insert into child (name, fatherid) values (?, ?)


但是数据库中的数据都是完整的了!!!


3·cascade = none,inverse = false

		<!-- cascade="none"且inverse="false" -->
<set name="children" cascade="none" inverse="false">
<key column="fatherid"/>
<one-to-many class="Child"/>
</set>


执行的sql语句

Hibernate: insert into father (name) values (?)
Hibernate: update child set fatherid=? where id=?
Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing:


级联取消,所以没有同时保存child,这时及时去跟新child的外键,只能出错了


4·cascade = none,inverse = true

		<!-- cascade="none"且inverse="true" -->
<set name="children" cascade="none" inverse="true">
<key column="fatherid"/>
<one-to-many class="Child"/>
</set>


执行的sql语句

Hibernate: insert into father (name) values (?)



cascade=none,没有级联保存child,所以child表中没有数据;inverse=true,放弃维护关联关系,所以没有去跟新child的外键,所以就不会报异常


多对多:



在多对多关系中,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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值