双向关联与inverse设定
来源:互联网 发布:淘宝店哪些东西利润高 编辑:程序博客网 时间:2024/04/30 13:55
之前我们对User与Room作了单向的多对一以及反过来的一对多关联,我们也可以让User与Room彼此参考,形成双向关联,就User与Room对象,具体来说,就是将程序如下设计:
User.java
package onlyfun.caterpillar;
public class User {
private long id;
private String name;
private Room room;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
}
Room.java
package onlyfun.caterpillar;
import java.util.*;
public class Room {
private long id;
private String address;
private Set users = new HashSet();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Set getUsers() {
return users;
}
public void setUsers(Set users) {
this.users = users;
}
}
而其对应的映射文件如下,首先是User.hbm.xml:
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="USER">
<id name="id" column="USER_ID" unsaved-value="0">
<generator class="increment"/>
</id>
<property name="name">
<column name="NAME" length="16" not-null="true"/>
</property>
<many-to-one name="room"
column="ROOM_ID"
class="onlyfun.caterpillar.Room"/>
</class>
</hibernate-mapping>
再来是Room.hbm.xml:
Room.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.Room" table="ROOM">
<id name="id" column="ROOM_ID" unsaved-value="0">
<generator class="increment"/>
</id>
<property name="address" type="string"/>
<set name="users" table="USER" cascade="all">
<key column="ROOM_ID"/>
<one-to-many class="onlyfun.caterpillar.User"/>
</set>
</class>
</hibernate-mapping>
这就形成了User与Room之间的双向关联映像,我们可以使用以下的程序进行测试:
HibernateTest.java
import onlyfun.caterpillar.*;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateTest {
public static void main(String[] args) throws HibernateException {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Room room = new Room();
room.setAddress("NTU-M8-419");
User user1 = new User();
user1.setName("bush");
User user2 = new User();
user2.setName("bush");
/*
* 因为没有设定inverser,所以只须从parent维护即可
*/
//user1.setRoom(room);
//user2.setRoom(room);
room.getUsers().add(user1);
room.getUsers().add(user2);
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
session.save(room);
tx.commit();
session.close();
sessionFactory.close();
}
}
基本上就数据的储存来说,这样就已经足够,但这样的设计会有效能问题,显然的,这个程序将Room与User之间的关联交由Room来维持,就Room 而言,它要先储存自已,然后储存其所包括的多个User,之后再对每一个User更新(update)对自己(Room)的关联,具体而言,这个程序必须实行以下的SQL:
Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: update USER set ROOM_ID=? where USER_ID=?
Hibernate: update USER set ROOM_ID=? where USER_ID=?
就Room而言,它并不知道其所包括的User是不是一个已储存的对象,或者即使为已储存对象,也不知道USER表格 上的ROOM_ID是不是参考至ROOM表格的ROOM_ID上,所以它必须针对自己所包括的User对象一个个进行更新,以确保USER表格上的 ROOM_ID是指向自己。
如果将关联的维护交给User的话会比较容易,因为每个User都对应至一个Room,在储存时并用像Room一样必须对Set中的每个对象作检查,为 了将关联的维护交给User,我们可以在Room.hbm.xml中的<set>修改,加上inverse="true",表示将关联的维护「反过来」交给User作:
Room.java
<set name="users" table="USER" inverse="true" cascade="all">
<key column="ROOM_ID"/>
<one-to-many class="onlyfun.caterpillar.User"/>
</set>
由于将关联的维护交给User来作了,所以我们必须在储存时,明确的将Room设定给User,也就是说,必须这样作:
/*
* 因为有user维护关联,所以必须呼叫setRoom
*/
user1.setRoom(room);
user2.setRoom(room);
room.getUsers().add(user1);
room.getUsers().add(user2);
这比不加上inverse="true"设定时多了个指定的动作,您必须多键几个字,所带来的是效率上的增加,Hibernate的持久层管理员会先储存Room,然后储存User,如此就可以省去之前再进行更新的动作,具体来说,就是会执行以下的SQL:
Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
与先前不同的是,由于关联交给了User维护,所以这次Room不用一一更新USER以确定每个ROOM_ID都指向自已。
如果指定了inverse="true",而不确实的将Room指定给User会如何?那么User与Room会各自储存,但彼此没有关联,也就是User将不会参考至Room,USER表格的ROOM_ID将为null,例如:
mysql> select * from USER;
+---------+------+---------+
| USER_ID | NAME | ROOM_ID |
+---------+------+---------+
| 1 | bush | NULL |
+---------+------+---------+
mysql> select * from ROOM;
+---------+------------+
| ROOM_ID | address |
+---------+------------+
| 1 | NTU-M8-419 |
+---------+------------+
作个总结,在设立双向关联时,关联由多对一中「多」的哪一方维护,会比由「一」的哪一方维护来的方便,在Hibernate可以藉由inverse来设定,不设定inverse基本上也可以运行,但是效能会较差。
设定了inverse,必须要明确的设定双方的参考,以这个主题的例子,Room要设定给User,而User也要知道Room的存在,这比不设定 inverse需要键入较多的字,但从另一方面,比较符 合程序设计的直觉(单看User与Room类别,两者要互相参考时,本来就要明确设定)。
- 双向关联与inverse设定
- Hibernate入门21 - 双向关联与inverse设定
- Hibernate单、双向关联与inverse属性
- Hibernate一对多双向关联及inverse的作用
- Hibernate一对多双向关联及inverse的作用
- Hibernate学习日志一:正确理解hibernate的inverse,双向关联
- hibernate单向关联与双向关联
- Hibernate中的双向多对一关联以及 inverse属性、cascade属性的用法
- Hibernate 关系关联映射和cascade与inverse
- 【spring】一般情况下,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true
- hibernate.hbm.xml 中对多对多双向关联的 中inverse镜像的使用
- 关联映射-双向关联
- 搞定Hibernate表与表之间的关联,搞懂cascade、inverse、lazy等属性
- 搞定Hibernate表与表之间的关联,搞懂cascade、inverse、lazy等属性
- 搞定Hibernate表与表之间的关联,搞懂cascade、inverse、lazy等属性
- Hibernate双向关联配置用set与bag的总结
- Hibernate中的多对一单向与双向关联
- hibernate双向一对一主键关联映射XML与注解版
- 滚动条定位控制
- 如何固定table的表头
- Web的桌面提醒(Popup,类似msn,outlook等的信息提示)
- Hibernate入门20 - cascade持久化
- 简单验证码的产生
- 双向关联与inverse设定
- 帮看网:web2.0的网页监控服务
- Google公布06年十大搜索词 “视频/video”居首
- 多行文本框限制输入字符长度(两种方法)
- 浅显的谈谈证券公司的信息化
- 取得控件绝对位置
- Windows Vista:通信基础结构
- TextBox上实现右键菜单
- Java开发者必去的技术网站