Hibernate入门23 - 多对多实体映像

入门 23 - 多对多实体映像

 假设现在有User与Server两个类别,一个User可以被授权使用多台Server,而在Server上也记录授权使用它的使用者,就User与Server两者而言即使多对多的关系。
 在程序设计时,基本上是不建议直接在User与Server之间建立多对多关系,这会使得User与Server相互依赖,通常会透过一个中介类别来维护两者之间的多对多关系,避免两者的相互依赖。
 如果一定要直接建立User与Server之间的多对多关系,Hibernate也是支持的,基本上只要您了解之前介绍的几个实体映像,建立多对多关联在配置上并不困难。
 先看一下我们设计的User与Server类别:

User.java

package onlyfun.caterpillar;

 

import java.util.*;

 

public class User {

    private long id;

    private String name;

    private Set servers = new HashSet();

  

    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 Set getServers() {

        return servers;

    }

    

    public void setServers(Set servers) {

        this.servers = servers;

    }    

}

 

Server.java

package onlyfun.caterpillar;

 

import java.util.*;

 

public class Server {

   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;

   }

}


 这边各使用HashSet来保存彼此的关系,在多对多关系映射上,我们可以建立单向或双向关系,这边直接介绍双向关系映像,并藉由设定inverse= "true",将关系的维护交由其中一方来维护,这么作的结果,在原始码的撰写上,也比较符合Java的对象关系维护,也就是双方都要设置至对方的参考。
 首先来看看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>

    

        <set name="servers"

             table="USER_SERVER"

             cascade="save-update">

            

            <key column="USER_ID"/>

            <many-to-many class="onlyfun.caterpillar.Server"

                          column="SERVER_ID"/>          

        </set>

                        

    </class>

 

</hibernate-mapping>


 在数据库中,数据表之间的多对多关系是透过一个中介的数据表来完成,例如在这个例子中,USER数据表与USER_SERVER数据表是一对多,而 USER_SERVER对SERVER是多对一,从而完成USER至SERVER的多对多关系,在USER_SERVER数据表中,将会有USER_ID 与SERVER_ID共同作为主键,USER_ID作为一个至USER的外键参考,而SERVER_ID作为一个至SERVER的外键参考。
 来看看Server.hbm.xml映射文件:

Server.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.Server" table="SERVER">

 

        <id name="id" column="SERVER_ID" unsaved-value="0">

            <generator class="increment"/>

        </id>

 

        <property name="address" type="string"/>

      

        <set name="users"

             table="USER_SERVER"

             inverse="true"

             cascade="save-update">

            

             <key column="SERVER_ID"/>

             <many-to-many class="onlyfun.caterpillar.User"

                           column="USER_ID"/>

        </set>

    </class>

 

</hibernate-mapping>


 设置上与User.hbm.xml是类似的,只是增加了inverse="true",表示将关系的维护交由另一端,注意我们在User与 Server的cascade都是设置为save-update,在多对多的关系中,all、delete等cascade是没有意义的,因为多对多中, 并不能因为父对象被删除,而造成被包括的子对象被删除,因为可能还有其它的父对象参考至这个子对象。
 我们使用下面这个程序来测试:

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();

      

        Server server1 = new Server();

        server1.setAddress("PC-219");

        Server server2 = new Server();

        server2.setAddress("PC-220");

        Server server3 = new Server();

        server3.setAddress("PC-221");

      

        User user1 = new User();

        user1.setName("caterpillar");

        User user2 = new User();

        user2.setName("momor");

      

        user1.getServers().add(server1);

        user1.getServers().add(server2);

        user1.getServers().add(server3);

        server1.getUsers().add(user1);

        server2.getUsers().add(user1);

        server3.getUsers().add(user1);

      

        user2.getServers().add(server1);

        user2.getServers().add(server3);

        server1.getUsers().add(user2);

        server3.getUsers().add(user2);

      

        Session session = sessionFactory.openSession();

        Transaction tx= session.beginTransaction();

        session.save(user1);

        session.save(user2);

 

        tx.commit();

        session.close();

 

        sessionFactory.close();

    }

}


 注意由于设定了inverse="true",所以必须分别设定User与Server之间的相互参考,来看看实际上数据库中是如何储存的:

mysql> select * FROM USER;

+---------+-------------+

| USER_ID | NAME        |

+---------+-------------+

|       1 | caterpillar |

|       2 | momor       |

+---------+-------------+

2 rows in set (0.00 sec)

 

mysql> select * FROM USER_SERVER;

+-----------+---------+

| SERVER_ID | USER_ID |

+-----------+---------+

|         1 |       1 |

|         2 |       1 |

|         3 |       1 |

|         1 |       2 |

|         2 |       2 |

+-----------+---------+

5 rows in set (0.00 sec)

 

mysql> select * FROM SERVER;

+-----------+---------+

| SERVER_ID | address |

+-----------+---------+

|         1 | PC-219  |

|         2 | PC-221  |

|         3 | PC-220  |

+-----------+---------+

3 rows in set (0.00 sec)


 有关于多对多更多的例子与说明,您可以参考Hibernate in Action的6.3。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值