在 多對一 、一對多 中都是單向關聯,也就是其中一方關聯到另一方,而另一方不知道自己被關聯。
如果讓雙方都意識到另一方的存在,這就形成了雙向關聯,在多對一、一對多的例子可以改寫一下,重新設計User類別如下:
package onlyfun.caterpillar;
public class User { private Integer id; private String name; private Room room;
public User() {}
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 Room getRoom() { return room; }
public void setRoom(Room room) { this.room = room; } }
Room類別如下:
package onlyfun.caterpillar;
import java.util.Set;
public class Room { private Integer id; private String address; private Set users;
public Room() {}
public Integer getId() { return id; }
public void setId(Integer 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; }
public void addUser(User user) { users.add(user); }
public void removeUser(User user) { users.remove(user); } }
如此,User實例可參考至Room實例而維持多對一關係,而Room實例記得User實例而維持一對多關係。
在映射文件方面,可以如下撰寫:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="user"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id>
<property name="name" column="name" type="java.lang.String"/>
<many-to-one name="room" column="room_id" class="onlyfun.caterpillar.Room" cascade="save-update" outer-join="true"/> </class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.Room" table="room"> <id name="id" column="id"> <generator class="native"/> </id>
<property name="address" column="address" type="java.lang.String"/>
<set name="users" table="user" cascade="save-update"> <key column="room_id"/> <one-to-many class="onlyfun.caterpillar.User"/> </set> </class>
</hibernate-mapping>
映射文件雙方都設定了cascade為save-update,所以您可以用多對一的方式來維持關聯:
User user1 = new User(); user1.setName("bush");
User user2 = new User(); user2.setName("caterpillar");
Room room1 = new Room(); room1.setAddress("NTU-M8-419");
user1.setRoom(room1); user2.setRoom(room1);
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();
session.save(user1); session.save(user2);
tx.commit(); session.close();
或是反過來由一對多的方式來維持關聯:
User user1 = new User(); user1.setName("bush");
User user2 = new User(); user2.setName("caterpillar");
Room room1 = new Room(); room1.setUsers(new HashSet()); room1.setAddress("NTU-M8-419"); room1.addUser(user1); room1.addUser(user2);
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();
session.save(room1);
tx.commit(); session.close();
這邊有個效率議題可以探討,上面的程式片段Hibernate將使用以下的SQL進行儲存:
Hibernate: insert into room (address) values (?) Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: update user set room_id=? where id=? Hibernate: update user set room_id=? where id=?
上面的程式寫法表示關聯由Room單方面維持,而主控方也是Room,User不知道Room的room_id是多少,所以必須分別儲存Room與 User之後,再更新user的room_id。
在一對多、多對一形成雙向關聯的情況下,可以將關聯維持的控制權交給多的一方,這樣會比較有效率,理由不難理解,就像是在公司中,老闆要記住多個員工的姓名快,還是每一個員工都記得老闆的姓名快。
所以在一對多、多對一形成雙向關聯的情況下,可以在「一」的一方設定控制權反轉,也就是當儲存「一」的一方時,將關聯維持的控制權交給「多」的一方,以上面的例子來說,可以設定Room.hbm.xml如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.Room" table="room"> <id name="id" column="id"> <generator class="native"/> </id>
<property name="address" column="address" type="java.lang.String"/>
<set name="users" table="user" cascade="save-update" inverse="true"> <key column="room_id"/> <one-to-many class="onlyfun.caterpillar.User"/> </set> </class>
</hibernate-mapping>
由於關聯的控制權交給「多」的一方了,所以直接儲存「一」方前,「多」的一方必須意識到「一」的存在,所以程式片段必須改為如下:
User user1 = new User(); user1.setName("bush");
User user2 = new User(); user2.setName("caterpillar");
Room room1 = new Room(); room1.setUsers(new HashSet()); room1.setAddress("NTU-M8-419"); room1.addUser(user1); room1.addUser(user2);
// 多方必須意識到單方的存在 user1.setRoom(room1); user2.setRoom(room1); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();
session.save(room1);
tx.commit(); session.close();
上面的程式片段Hibernate將使用以下的SQL:
Hibernate: insert into room (address) values (?) Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: insert into user (name, room_id) values (?, ?)
如果控制權交給另一方了,而另一方沒有意識到對方的存在的話會如何?試著將上面的程式片段中user1.setRoom(room1);與 user2.setRoom(room1);移去,執行之後,您會發現資料庫中room_id會出現null值,這種結果就好比在 多對一 中,您沒有分配給User一個Room,理所當然的,room_id會出現null。
|
相关推荐
PowerDesigner 常用设置大全。自己在平时工作中用到的。总结了一下。文件为pdf文档。带书签的。设置方法图文并茂. 设置1:取消Name与Code的联动 设置2:生成SQL的时候,把NAME自动更新到Comment列 设置3:如何去除...
powerdesigner 15 Oracle为表指定表空间,双击表,在弹出的属性页里面选择 Physical Options (Common)选项卡
PowerDesigner概念模型实体、属性的创建.pdf 学习资料 复习资料 教学资源
Sybase PowerDesigner 9.5 使用教程(中文) 讲得很详细
PowerDesigner中文使用手册,超好用的中文手册,表建模,关系建模...
这个是PowerDesigner数据库建模工具的基础时间用教程,例如一对多,多对一,多对多的详细教程
powerDesigner 英文字段名修改为中文 这样比对不同表的时候对应字段
PowerDesigner 设置集锦 ,详细介绍PowerDesigner 的各项配置
PowerDesigner16.5_中文补丁PowerDesigner16.5_中文补丁PowerDesigner16.5_中文补丁
PowerDesigner中Table选择不到
PowerDesigner 15-EA中文文档 PowerDesigner 15-EA中文文档 PowerDesigner 15-EA中文文档 PowerDesigner 15-EA中文文档 PowerDesigner 15-EA中文文档 PowerDesigner 15-EA中文文档
svn中文手册 PowerDesigner中文手册
powerdesigner
实验一Powerdesigner
把powerdesigner中表名为汉字以及列名为汉字的转为汉语拼音抽头的方法把powerdesigner中表名为汉字以及列名为汉字的转为汉语拼音抽头的方法
powerdesigner11中文教程.rar
Powerdesigner中连接Mysql数据库
使用PD(PowerDesigner)自动生成Hibernate的POJO文件及xml配置文件
PowerDesigner是Sybase的企业建模和设计解决方案,采用模型驱动方法,将业务与IT结合起来,可帮助部署有效的企业体系架构,并为研发生命周期管理提供强大的分析与设计技术。PowerDesigner独具匠心地将多种标准数据...