Hibernate关联映射(2)2015-07-11

接上篇。

一对一双向关联的配置

说明:仍是以person与address为例,在person类中有一个类型为address的变量,在address类中有一个类型为person的变量。

一对一  主键  双向关联配置(如下)

<hibernate-mapping> 
  <class name="entity.Person" table="person"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <generator class="identity" /> 
    </id> 
    <property name="name" type="java.lang.String"> 
      <column name="name" length="24" not-null="true"> 
        <comment>姓名</comment> 
      </column> 
    </property> 
    <!-- cascade="all":在保存person对象的时候,级联保存person对象关联的address对象    --> 
    <one-to-one name="address" cascade="all" /> 
  </class> 
</hibernate-mapping>
<hibernate-mapping> 
  <class name="entity.Address" table="address" catalog="mydb"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <!-- class="foreign": 一对一主键映射中,使用另外一个相关联的对象的标识符 --> 
      <generator class="foreign"> 
        <param name="property">person</param> 
      </generator> 
    </id> 
    <property name="detail" type="java.lang.String"> 
      <column name="detail" length="120" not-null="true"> 
        <comment>详细地址</comment> 
      </column> 
    </property> 
    <!-- 表示在address表存在一个外键约束,外键参考相关联的表person --> 
    <one-to-one name="person" constrained="true" /> 
  </class> 
</hibernate-mapping>
一对一  外键 双向关联配置(如下)

<hibernate-mapping> 
  <class name="entity.Person" table="person"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <generator class="identity" /> 
    </id> 
    <property name="name" type="java.lang.String"> 
      <column name="name" length="24" not-null="true"> 
        <comment>姓名</comment> 
      </column> 
    </property> 
    <one-to-one name="address" cascade="all" /> 
  </class> 
</hibernate-mapping>
<hibernate-mapping> 
  <class name="entity.Address" table="address" catalog="testdb"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <generator class="identity" /> 
    </id> 
    <property name="detail" type="java.lang.String"> 
      <column name="detail" length="120" not-null="true"> 
        <comment>详细地址</comment> 
      </column> 
    </property> 
    <many-to-one name="person" class="entity.Person" 
      fetch="select" unique="true"> 
      <column name="personid"> 
        <comment>人的ID</comment> 
      </column> 
    </many-to-one> 
  </class> 
</hibernate-mapping>
一对一 连接表 双向关联配置(如下)

<hibernate-mapping>
    <class name="com.lavasoft.sx._1_1_tab.Person11tab_sx" table="PERSON_11tab_sx">
        <id name="personid">
            <generator class="identity"/>
        </id>
        <property name="name"/>
        <property name="age"/>
        <join table="join_11tab_sx"
              optional="true">
            <key column="personid"
                 unique="true"/>
            <many-to-one name="address11tab_sx"
                         column="addressid"
                         not-null="true"
                         unique="true"/>
        </join>
    </class>
</hibernate-mapping>
<hibernate-mapping>
    <class name="com.lavasoft.sx._1_1_tab.Address11tab_sx" table="ADDRESS_11tab_sx">
        <id name="addressid">
            <generator class="identity"/>
        </id>
        <property name="addressdetail"/>
        <join table="join_11tab_sx"
              optional="true"
              inverse="true">
            <key column="addressid"
                 unique="true"/>
            <many-to-one name="person11tab_sx" column="personid"
                         not-null="true" unique="true"/>
        </join>
    </class>
</hibernate-mapping>

*********一对一  主键 双向关联*************

首先,还是我们根据需求,确定用一对一  主键 双向关联,那么,两个表肯定是同样的主键(要不还能是哪一列充当俩个表之间的桥梁),有人会说,我可以在person表的最后添加上addres表的主键列,也可以架起两个表之间的桥梁,但是这样就不是主键的关联了而是外键方式的关联。

同样,我们一行一行的往下读,前面的太简单就不多说了,在person表中,最后出现一个one-to-one,指定了关联查询address表后,把查到的数据封装成address对象,复制给name=“”引号中的变量,供person调用(name=“”引号内的变量名是在person类内作为成员变量存在的)。

可能有人注意到了,上篇说道,有foreign的时候,采用one-to-one 啊,确实,在person中没有配置这个啊,这是因为,这里设置的person表可以生成主键,但是address表的主键就得通过foreign来设置了。因为是双向关联的嘛,总得有一个是主体,另一个引用主体的内容。

最后,在person中有个cascade="all" 表示对增删改查都得做级联操作,也就是更改两个表的内容。
再看address的配置,对主键的增长方式generator选择的是foreign,引用别的表的主键作为自己的主键。引用的是谁的呢?标签体内写着一个叫“person”的属性。也就是hibernate会在address类中找一个名为person的变量,看它的类型是什么,再看这个类创建有没有对应的表,有的话引用它的主键。

同样,最后有个one-to-one标签。表示关联查询后,查询到的结果要封装成person属性对应的类的对象。然后赋给person属性(通过address类中写好的get/set方法),以供address调用。

one-to- one的双向关联中,必须设置constrained=true,要不然会有重复数据读。(这一句为引用,参考附在最后)

*********一对一 外键 双向关联*************

确定好使用外键关联查询的话,也就想上面分析的,得在其中一张表的最后一列添加另一张表的主键,架起两张表的桥梁,就可以关联查询啦。

这里是在address表后添加person的主键作为外键。

在看了上一篇的同学可能会有疑问,为什么person表用个的是one-to-one而address表用的是more-to-one呢?其实,我刚刚也在为什么,现在大体明白了,简述下:上一篇中对one-to-one的使用场景概括的不够笼统、不够抽象,上篇说道在遇到id的generator是foreign的时候用one-to-one,其实现在看来应该是,当确定两个表之间的桥梁已将架好之后,若表还需要进行关联查询并且符合一对一的条件就用one-to-one。

已现在的配置为例子,address的配置中用的more-to-one在address最后一列加上了列字段为personid的列,引用的是person表的主键。所以一是两个表之间的桥梁已经架好了,而是是表address使用的more-to-one就能被hibernate识别并完成关联person表查询的功能。但再看person表,它也需要进行关联查询,查询address的内容,并且符合one-to-one的条件。

好了,上面是规律的总结。那我们再深入下,从hibernate看到one-to-one后会执行什么动作再来分析。其实hibernate看到one-to-one和more-to-one标签后,应该会想:嗯,这时要我去进行关联查询了,让我看看标签的name=“”引号内的属性名是什么(如在address配置中,就是person),然后找到属性对应的类型(也就是person类),查看hibernate有没有创建该类对应的表(person类对应的表),通过架好的桥梁(相同的主键、外键、连接表)进行关联查询(查询person的表),结果封装成那个类的对象(封装成person类的对象),赋值到属性中(赋值给address类中的person类型的成员变量),供调用。

从上面的功能来看,one-to-one和more-to-one的不同也就是表的关系不同,一对一的表关系或多对一的表关系,而且more-to-one还会转化成one-to-one。

但是one-to-one和more-to-one不同的是,hibernate看到more-to-one,会在该表中创建一列,列名根据column指定,若没有写column,则默认与name=“”一致,也就是说,more-to-one有能力搭建桥梁,而one-to-one只能使用这个桥梁进行关联查询。

所以,我们回想下,在一对一的外键单向关联时,使用的是more-to-one,利用unique=“true”使其变成one-to-one。而一对一的主键单向关联之所以能够使用one-to-one,就是因为foreign属性把桥梁搭建好了。

理解了hibernate遇到one-to-one和more-to-one后的不同执行过程,我们在看一下more-to-one,利用unique=“true”使其变成one-to-one,应该是升级版的one-to-one,它也能搭建桥梁了。我们再从逻辑上理解下more-to-one转为one-to-one的过程。

这里要理解的是:more-to-one的意思,谁是more谁是one。还是现在一对一 外键 双向关联的例子,在address的配置中,写的是more-to-one,也就是可以有more个address对应one个person。在数据表上的体现就是:more条记录或说数据的addressid(根据主键特性,它们肯定是不同的)都有相同的(one个)personid值。而我们在more-to-one中指定unique=“true”,也就是说:不再是more个address对应one个person,它要求address是唯一的,那就成了one个address对应one个person。是more-to-one的一个特例,虽然写起来还是more-to-one,但内涵已变成one-to-one。同时它又具有one-to-one不具有的搭建桥梁的能力,所以说是升级版的one-to-one。

*********一对一 连接表 双向关联*************

当确定使用一对一 连接表 双向关联后,我们分析下:

有了上一篇的基础,就好理解了。假设hibernate一行一行的看,看到join后就知道,奥,原来是要创建一个连接表当作桥梁啊,好我给你们创建一个,名字就叫你后面紧跟着写的table=“”引号中的内容。并且hibernate还挺聪明,知道是要通过连接表(中间表)进行关联查询,那当前正在配置的这张表的主键妥妥的得放入连接表(中间表)才行。(中间表的逻辑就是把要关联查询的两个表的主键都放到这一张表中,A表的主键对应着B表的主键,选择A表的一条数据后,根据该数据的主键一般是id,到中间表查找对应的B表的id,再根据找到的B表的id到B表查询出数据。)

hibernate就是这么聪明,所以接下来的key中,只让你写列名column=“”,也就是为该表的主键放到中间表某一列的列字段起个名字。接下来就是more-to-one加上unique=“true”,变成升级版的one-to-one,可以搭建桥梁还能关联查询。

所以就在连接表(中间表)添加了一个叫column=“addressid”的列字段,与该字段对应的是person类中一个叫做name="address11tab_sx" 名为address11tab_sx的变量,打开person类看到变量address11tab_sx是address类型的,hibernate就很聪明,找了下address类是否创建了对应的表。

根据<class name="com.lavasoft.sx._1_1_tab.Address11tab_sx" table="ADDRESS_11tab_sx">,hibernate找到了这张表,并把主键内容加到连接表(中间表)的addressid列字段中。

但是要小心,这里有个小坑。那就是:

在address和person表的配置中,都会配置连接表(中间表)的列字段名字。我们要使其名字统一。

那为什么都要设置名字呢?如果大家还记得hibernate看到more-to-one后执行的动作或许会理解。

more-to-one是设置在join标签中,也就是在连接表中设置(虽然看起来是在person的配置中),所以在hibernate在连接表开辟一个列,并自动把主键所在列搬过去,然我们制定这个列的名称之外,我们还要搭建person表与连接表的桥梁,所以要用到more-to-one。同理,也需要搭建起address表和连接表的桥梁,这样最终才能实现person表和address表的关联。所以都要用到more-to-one来分别搭建两表与连接表间的桥梁。

在person中我们要指定主键在连接表的列字段,同样,在address中我们也要指定它的主键在连接表的列字段。这样就相当于中间表的两个列字段已经确定了。而在more-to-one中,如果我们不指定column的值,默认与name的值相同。这将很可能导致问题。

以person举例,person已经指定了person的主键在连接表中的列名叫做personid,在more-to-one中如果不设置column的值,那么address的主键所在列会默认同name一样,也就是address11tab_sx。然而在address中我们又指定了address的主键在连接表的列名叫addressid。这就会冲突。

当然,以上是我的理解,按照我推测的规则,如果指定列名不妥,会出错。当然不排除hibernate够聪明,它以<key>标签中的 column值作为最终参考,那是再好不过了,我们就可以不必写more-to-one中的column值,它自己去判断。这个推测还需要实际中去实验一下。

****************一对多 双向关联配置就这样********

下面是参考的资料:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值