chho的专栏

对于整个世界我微不足道,但是我对于自己确是全部

常浩ID:chho
75204次访问,排名1302(-1)好友0人,关注者1
chho的文章
原创 106 篇
翻译 0 篇
转载 0 篇
评论 24 篇
chho的公告


名字:Chho
JAVA程序员,现在对Linux产生了浓厚的兴趣。

我的Mail:
最近评论
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Hibernate入门23 - 多对多实体映像收藏

    新一篇: Hibernate入门24 - 延迟初始 Lazy Initialization | 旧一篇: Hibernate入门22 - 一对一实体映像

    入门 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。

    发表于 @ 2005年01月27日 20:39:00|编辑

    新一篇: Hibernate入门24 - 延迟初始 Lazy Initialization | 旧一篇: Hibernate入门22 - 一对一实体映像

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © chho