Hibernate关联映射(4)2016-07-13

继续今天理解一对多(多对一)双向关联。由于是双向关联,所以一对多和多对一是同一种情况。

还是用person和address的例子。一个person有多个address。这次有点复杂,把实体类的结构贴出来:

public class Person1nfk_sx implementsSerializable {

   private int personid;

   private String name;

   private int age;

   private Set addresses=new HashSet();

 

public class Address1nfk_sx implementsSerializable {

   private int addressid;

   private String addressdetail;

privatePerson1nfk_sx person1nfkSx;

区别于一对多(一个person对应多个address)的单向关联,这次的双向关联,在adress中加了person的对象作为address的成员变量。

一对多双向关联有两种方式:外键、连接表

一对多  外键 关联配置(如下):

 

<hibernate-mapping>
    <class name="com.lavasoft.sx._1_n_fk.Person1nfk_sx" table="PERSON_1nfk_sx">
        <id name="personid">
            <generator class="identity"/>
        </id>
        <property name="name"/>
        <property name="age"/>
        <!--映射集合属性,关联到持久化类-->
        <set name="addresses" inverse="true" cascade="all">
            <!--column用于指定外键列名-->
            <key column="personid" not-null="true"/>
            <!--映射关联类-->
            <one-to-many class="com.lavasoft.sx._1_n_fk.Address1nfk_sx"/>
        </set>
    </class>
</hibernate-mapping>
 
<hibernate-mapping>
    <class name="com.lavasoft.sx._1_n_fk.Address1nfk_sx" table="ADDRESS_1nfk_sx">
        <id name="addressid">
            <generator class="identity"/>
        </id>
        <property name="addressdetail"/>
        <!--映射关联属性,column属性指定外键列名-->
        <many-to-one name="person1nfk"
                     class="com.lavasoft.sx._1_n_fk.Person1nfk_sx"
                     fetch="select"
                     cascade="save-update">
            <column name="personid" not-null="true"/>
        </many-to-one>
    </class>
</hibernate-mapping>

一对多  连接表 关联配置(如下):

 

<hibernate-mapping>
    <class name="com.lavasoft.sx._1_n_tab.Person1ntab_sx" table="PERSON_1ntab_sx">
        <id name="personid">
            <generator class="identity"/>
        </id>
        <property name="name"/>
        <property name="age"/>
        <!--映射集合属性,关联到持久化类-->
        <!--table="join_1ntab_sx"指定了连接表的名字-->
        <set name="addresses"
             table="join_1ntab_sx"
             cascade="all">
            <!--column="personid"指定连接表中关联当前实体类的列名-->
            <key column="personid" not-null="true"/>
            <!--unique="true"表示当前实体类是"1",不是"n"-->
            <many-to-many column="addressid"
                          unique="true"
                          class="com.lavasoft.sx._1_n_tab.Address1ntab_sx"/>
        </set>
    </class>
</hibernate-mapping>
 
<hibernate-mapping>
    <class name="com.lavasoft.sx._1_n_tab.Address1ntab_sx"
           table="ADDRESS_1ntab_sx">
        <id name="addressid">
            <generator class="identity"/>
        </id>
        <property name="addressdetail"/>
        <!--映射关联属性,column属性指定外键列名-->
        <join   table="join_1ntab_sx"
                inverse="true"
              optional="true">
            <key column="addressid"/>
            <many-to-one name="person1ntab_sx"
                         column="personid"
                         cascade="all"
                         not-null="true"/>
        </join>
    </class>
</hibernate-mapping>

*****一对多 外键 关联*******

采用外键关联,不难想象,是把person的主键值作为address表的外键列(这是因为一个person可以有多个address,person具有唯一性,将person的主键存到address的中,每个address都只有一个person的主键值,易存取和查询。反过来,将address存到person中,一个person有多个address,若将所有address的主键值存到对应的person行中,取出后还要将多个address解析成一个个的形式,再进行查询;由于主键的唯一性,不允许我们复制同一个person行,也就否定了这样的想法:复制同一个person行,每行只有一个address的主键存进去)。

既然是把person的主键值作为address表的外键列,那person表的配置是和一对多的单向关联差不多的。都是写set标签,里面写key标签,然后来个one-to-many的标签。

有人可能发现了,这里的set标签里没写table=“”,按照上篇写的配置,应该写上将person的主键放到哪个表里面。这里没写也算是验证了上篇说的验证机制。再回顾一下:当hibernate看到set时,还不确定是外键方式还是连接表方式,即使我们把table的值写上address表的表名,它现在也是不知道的,它在看到我们选择使用的下一个标签one-to-many后,才知道我们是外键关联。所以上篇说的验证机制是:根据table所指的表名和one-to-many中calss的类,判断是不是该calss类所对应的table表。如果我们不在set中写table,那hibernate就会直接根据class找到该表,然后插入一列叫做key标签中的column,也就是叫做personid,它最为address的外键,在address和person中建立了联系。

现在person能关联到到address了,靠的是one-to-many标签(第二篇说过one-to-one与many-to-one的异同点,这里我认为one-to-many、many-to-many与many-to-one作用是一样的)。接下来就是配置address使address能通过已经搭建好的桥梁关联到person。

很显然,对address就要用many-to-one标签了,name="person1nfk"是指,在address类中有个叫person1nfk的成员变量,我要告诉hibernate,你关联查询后要把查询后的结果封装好赋值给person1nfk。class="com.lavasoft.sx._1_n_fk.Person1nfk_sx",既说明了person1nfk的类型,也是说要去哪张表关联查询(class="com.lavasoft.sx._1_n_fk.Person1nfk_sx"所对应的表,也就是person表)。

columnname="personid"是指,要hibernate根据address的这一列作为外键,关联查询person表。这里要注意column name="personid"要与person表中写的<keycolumn="personid" not-null="true"/>相对应。若address与别的表也有外键关联,那么columnname=若指定错了列名,就会出现错误。

*****一对多 连接表 关联*******

连接表关联的方式中,person表的配置也是一样,但这里可以看到set中有table了,这里是必须要指定了,因为连接表可没有类和它对应,key表示在中间表join_1ntab_sx中有一列叫做column="personid",里面放的是person的主键值。many-to-many用unique="true"表达了一对多的含义(感觉可以直接使用one-to-many标签),column="addressid"指在中间表join_1ntab_sx中有addressid这一列,并且personid的一对多的“多”指的就是column="addressid"。既然是中间表,存放的肯定都是主键,那这个addressid是哪个表的主键呢?就由class指定。同时,将来关联查询后,很能根据这个class将数据封装返回。

接下来是addressid表的配置,由于它也要关联连接表,所以使用了join标签。

同样<keycolumn="addressid"/>把主键值放到连接表,那一列就叫addressid,这与上面配置的得一样。<many-to-one name="person1ntab_sx"  column ="personid"> name="person1ntab_sx"指的是address实体类中叫做person1ntab_sx的变量(感觉这里的many-to-one是可以写class属性的,经过实验确实可以写calss,如果要写的话就写personid类)column ="personid"指关联第三方表后,查第三方表的personid列,根据查出来的主键去person表中找到数据,并封装,返回赋值给name="person1ntab_sx"的变量。

如果这里写了class就好理解了,查到personid后,根据class对应的表,也就是person表,再去person表中找数据,但这里省略了,也就说明这个class不是必须的,那hibernate去查personid列找到主键值后,是怎么知道要去person表中根据personid查数据呢?所以说关于关联这块,千丝万缕联系太多。我们只能这样想,开发框架的大神并仅仅不是根据这个class来找,当已经在personid和person建立联系后,有没有class就不重要了,这并不是说所有的class都可以不写。

personid和person的联系建立是由于在person表配置时:<keycolumn="personid">。我们已经知道hibernate够聪明,知道要把person的主键放到连接表,只让我们指定列名,我们有理由相信,hibernate同时在这时候也把personid这个列名和person表建立了联系,当我们根据addressid在连接表查到对应的personid时,hibernate一看,咦,这个personid还与person表有联系,它就会去person表继续查数据,然后返回。

******参考资料***************

http://lavasoft.blog.51cto.com/62575/39398/  强烈推荐先看,博文写了14种情况下的配置,我就是看了这个再结合其他资料摸索的规律

 

http://blog.sina.com.cn/s/blog_62f0eaa80101bpaf.html

 

http://blog.sina.com.cn/s/blog_62f0eaa80101bpah.html

 

http://blog.csdn.net/sanjy523892105/article/details/7061602

 

http://blog.csdn.net/linminqin/article/details/6324567

 

http://blog.csdn.net/jialinqiang/article/details/8704538

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值