inverse=true

tone发表评论于2007-4-1 19:10:51

多對一一對多中都是單向關聯,也就是其中一方關聯到另一方,而另一方不知道自己被關聯。

如果讓雙方都意識到另一方的存在,這就形成了雙向關聯,在多對一、一對多的例子可以改寫一下,重新設計User類別如下:

User.java
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類別如下:

Room.java
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實例而維持一對多關係。

在映射文件方面,可以如下撰寫:

User.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.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>
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">
            <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如下:

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。


个人主页 | 引用回复 | 主人回复 | 返回 | 编辑 | 删除
 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值