`
menjoy
  • 浏览: 421907 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

双向关联与inverse设定

阅读更多
 之前我们对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
<!---->
<!---->
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
 
<hibernate-mapping></hibernate-mapping>
 
    <class table="USER" name="onlyfun.caterpillar.User"></class>
 
        <id name="id" unsaved-value="0" column="USER_ID"></id>
            <generator class="increment"></generator>
       
 
        <property name="name"></property>
            <column></column>
       
    
        <many-to-one name="room" span=""></many-to-one>
                     column="ROOM_ID"
                     class="onlyfun.caterpillar.Room"/>        
   
 

 再来是Room.hbm.xml:
Room.hbm.xml
<!---->
<!---->
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
 
<hibernate-mapping></hibernate-mapping>
 
    <class table="ROOM" name="onlyfun.caterpillar.Room"></class>
 
        <id name="id" unsaved-value="0" column="ROOM_ID"></id>
            <generator class="increment"></generator>
       
 
        <property name="address" type="string"></property>
      
       
            <key column="ROOM_ID"></key>
           <one-to-many class="onlyfun.caterpillar.User"></one-to-many>
       
   
 

 这就形成了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中的修改,加上inverse="true",表示将关联的维护「反过来」交给User作:
Room.java
            <key column="ROOM_ID"></key>
            <one-to-many class="onlyfun.caterpillar.User"></one-to-many>
       

 由于将关联的维护交给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类别,两者要互相参考时,本来就要明确设定)。
 

 

分享到:
评论

相关推荐

    Hibernate电子书(全)

    #### 双向关联与inverse设定 在实体之间存在双向关联的情况下,需要正确设置`inverse`属性,以避免循环引用的问题。正确设置`inverse`可以确保Hibernate在处理关联关系时的行为符合预期。 #### 一对一与多对多实体...

    Hibernate 入门

    - **双向关联与inverse设定**: - 在多对多、一对多等关联中管理引用方向。 - **延迟加载** (`LazyInitialization`): - 延迟加载关联对象,提高应用性能。 - **Session管理**: - 开启、关闭`Session`,管理事务...

    hibernate学习笔记

    #### 双向关联与inverse设定 - **双向关联**:表示两个实体之间相互引用的情况。 - **inverse设定**:通过`inverse="true"`属性指定由哪一方负责维护关系,以避免并发问题。 #### 一对一实体映射 - **描述**:一种...

    Hibernate学习笔记

    #### 双向关联与inverse设定 - **定义**:双向关联是指两个实体类之间存在相互引用的情况。 - **inverse设定**:通过`inverse="true"`指定哪个方向负责关联的维护。 #### 一对一实体映射 - **定义**:表示两个实体...

    Hibernate开发租房系统2 源码

    在一个双向一对多关联中,通常设定一方为“拥有”关系的一方,另一方为“被拥有”的一方。inverse属性用于指定哪一侧不负责维护关联关系。例如,如果将区设为inverse=true,那么在添加或删除街道时,不需要通过区...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     7.2 映射一对多双向关联关系  7.2.1 元素的inverse属性  7.2.2 级联删除  7.2.3 父子关系  7.3 映射一对多双向自身关联关系  7.4 改进持久化类  7.5 小结  7.6 思考题 第8章 通过Hibernate操纵对象(上) ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     7.2 映射一对多双向关联关系  7.2.1 元素的inverse属性  7.2.2 级联删除  7.2.3 父子关系  7.3 映射一对多双向自身关联关系  7.4 改进持久化类  7.5 小结  7.6 思考题 第8章 通过Hibernate操纵对象(上) ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     7.2 映射一对多双向关联关系  7.2.1 元素的inverse属性  7.2.2 级联删除  7.2.3 父子关系  7.3 映射一对多双向自身关联关系  7.4 改进持久化类  7.5 小结  7.6 思考题 第8章 通过Hibernate操纵对象(上) ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     7.2 映射一对多双向关联关系  7.2.1 元素的inverse属性  7.2.2 级联删除  7.2.3 父子关系  7.3 映射一对多双向自身关联关系  7.4 改进持久化类  7.5 小结  7.6 思考题 第8章 通过Hibernate操纵对象(上) ...

    最新Java面试宝典pdf版

    12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...

    Java面试宝典-经典

    12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...

    java面试题大全(2012版)

    12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...

    Java面试宝典2012版

    12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中...

    java面试宝典2012

    12、写Hibernate的一对多和多对一双向关联的orm配置? 134 9、hibernate的inverse属性的作用? 134 13、在DAO中如何体现DAO设计模式? 134 14、spring+Hibernate中委托方案怎么配置? 134 15、spring+Hibernate中委托...

Global site tag (gtag.js) - Google Analytics