Hibernate逍遥游记——(二)对象—关系映射技术

本文详细介绍了Hibernate的对象关系映射技术,包括持久化类的属性访问、对象标识符(OID)设置、一对一、一对多、多对多等各种关联关系的映射方法,以及动态SQL语句的控制。通过示例解析了映射文件中的各个元素,如<property>、<many-to-one>、<set>等,帮助开发者深入掌握Hibernate的ORM技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.对象关系映射基础

1.1 持久化类的属性及访问方法

持久化类的访问方法有两个调用者:

  •  java应用程序:通过持久化类的getter和setter方法进行访问。
  •  Hibernate :通过持久化类的getter和setter方法或通过java的反射机制进行访问

注意:

java应用程序不能访问持久化类的private类型的getter、setter方法,而Hibernate可以。

持久化类中的属性类型可以是基本类型或包类型,他们对应相同的Hibernate映射类型。但基本类型无法表示null值,推荐使用包类型。

1.2 Hibernate访问持久化类属性的策略

通过设置映射文件中的<property>元素的access属性的方式。

  • access="property"(默认),指定Hibernate通过setXXX和getXXX方法访问持久化类属性(最佳实践)。
  • access="field",指定Hibernate通过java反射机制直接访问类的属性。

1.3 派生属性的映射

派生属性:持久化类的某些属性的值在运行时通过计算得出。

1)在持久化类中虽没有某个属性,表中有这个属性。

  解决:在持久化类中设置该属性对应的setter和getter方法,并加入处理逻辑,然后在映射文件中映射该属性,则Hibernate就可以访问。

2)持久化类中有某个属性如avgAge,但表中没有该属性。

  解决:通过<property>的formula来设置一个SQL表达式,Hibernate在运行时计算出派生属性的值。

1.4 控制Hibernate生成的insert和update语句

 HIbernate在初始化阶段,根据文件的映射信息,为所有的持久化类预定义SQL语句(insert、update、delete、select)并将其保存在SessionFactory的内置缓存中。

当session执行相应的方法时(save、update、delete、load、get),直接从缓存中调用预定义的SQL并绑定参数。

通过设置动态SQL语句提高性能, 即在持久化类的映射文件中将class的属性 dynamic-update设置成true,则Hibernate可以根据Session中保存的Monkey快照,在update时只会包含需要更新的字段。

注意:

HIbernate有两种配置文件:hibernate.properties和hibernate.cfg.xml。HIbernate默认会到classpath路径下加载hibernate.properties文件。 如果该文件不存在,则通过Configuration的configure()显示加载hibernate.cfg.xml。

2.映射对象标识符OID

2.1 对象标识符(OID)

  •  java语言使用内存地址来识别和区分同一个类的不同对象;
  •  关系数据库按主键值来识别和区分同一个表的不同记录;
  • Hibernate使用对象标识符(OID)来建立Session缓存中的对象和数据库表中记录的一一对应关系(session中对象的OID和数据库表的主键一一对应)。

2.2 主键设置自动增长

常用数据库主键设置自动增长:Mysql采用 auto_increment;MS SQL Server采用 identify ;Oracel使用序列(Sequence)中获取自动增长的标识符。

最佳实践:将持久化类的OID的setId()方法设置成private类型以防止Java应用程序随便修改OID。而将getId()设置成public使得Java应用程序可以读取持久化对象的OID。

2.3 Hibernate的内置标识符生成器

持久化类的映射文件中<generator>子元素的calss属性用来设定标识符生成器。

Hibernate的常用标识符生成器:increment、identity、sequence、hilo、native等。
  • increment:由Hibernate以递增的方式为代理主键赋值。在单个应用服务器上可以有效工作,不适合集群环境。
  • hilo:由HIbernate按照一种high/low算法来生成标识符。不依赖于底层的数据库系统。
  • identity:由底层的数据库来负责生成标识符。要求数据库把主键定义为自动增长字段类型。
  • sequence:由底层的数据库提供的序列来生成标识符。要求底层的数据库系统必须支持序列。
  • native:依据底层的数据库对自动生成标识符的支持能力,选择用identity、sequence或hilo标识符生成器。它能自动判断底层数据库提供的生成标识符机制。

最佳实践:使用native标识符生成器,可以跨数据库平台。

2.4 补充说明

关系数据库中的主键可以分为自然主键(具有业务含义)和代理主键(不具有业务含义),代理主键更加流行,且通常为整数类型。与此对应,在持久化类中应把OID定义为整数类型,Hibernate把OID定义为long、int或short。

3.映射一对多关联关系

说明:一对多关联与多对一关联在本节中意义等价。

在关系数据库中,只存在外键参照关系,而且总是由“many”的一方参照“one”的一方。实际上关系数据库中只存在多对一或一对一的单向关联。假设存在如下图3-1所示的关系:

图3-1 MONKEYS表参照TEAMS表


3.1 建立多对一的单向关联关系

持久化类Monkey与Team是多对一的关系,在Monkey中有一个Team类型的team属性。

public class Monkey {
          ...  

    private Team team;
        ...
  
}
Monkey通过Monkey.hbm.xml映射MONKEYS表,其中:
  • name映射NAME,类型相同String类型,使用<property>映射:
      <property name="name" type="string" column="NAME" />  <!--type="string"为Hibernate的映射类型-->
  •  team(Team类型)映射TEAM_ID(整型),类型不匹配,使用<many-to-one>映射     
  <many-to-one

            name="team"                       <!--持久化类Monkey中要映射的属性team-->

            column="TEAM_ID"                  <!--同持久化类的属性对应的表的外键TEAM_ID-->

            class="mypack.Team"               <!--表明team属性的类型为mypack.Team->

            cascade="save-update"             <!--默认为none,设置级联保存和更新-->

            lazy="false"                      <!--立即加载策略,默认为true-->

       />
说明:cascade的值设置成save-update,可以保证当Hibernate在持久化临时对象时会自动持久化其所关联的其他临时对象。也就是说,在保存或更新Monkey对象时,会自动保存或更新与之关联的Team对象。 

3.2 映射一对多双向关联

前面3.1中已经建立了Monkey端的多对一单向关联,再加上本节Team端的一对多关联,就是双向关联了。
  • 在Team中增加如下属性:  
   public class Team{
                  ...
                private Set monkeys = new HashSet();
                   ...
       }

最佳实践:在持久化类中声明接口类型的集合属性,并为他初始化为集合实现类的一个实例(可扩展、健壮性)。

  • Team通过Team.hbm.xm与TEAMS映射,· 映射monkeys属性(TEAMS表中没有与其对应的字段),使用<set>
   <set 
                name="monkeys"                           <!--持久化类Team中要映射的属性monkeys-->
                inverse="true"                           <!--控制权交给Monkey-->
                cascade="save-update"                    <!--默认为none,设置级联保存和更新-->
                >
        
            <key column="TEAM_ID" />                     <!--表明关联Monkey对应的表MONKEYS的外键-->       
            <one-to-many class="mypack.Monkey" />        <!--表明monkeys集合中的对象为Monkey类型-->
     </set>  
最佳实践:在建立一对多的双向关联关系时,应该在“one”的一方把<set>元素的inverse属性设置为true,可以提高应用的性能。在建立两个对象的双向关联时,同时修改关联两端的对象的相应属性。
  •    再议cascade

     delete—— 级联删除,删除一个持久化对象(如Team)时,会自动删除与之关联的持久化对象(Monkey)。“删除”是指将对象由持久化状态变成删除状态。

     all-delete-orphan—— 当存在父子关系时,在父方设置。说明:父子关系指由父方控制子方的持久化生命周期。如,Team删除或Team解除了与Monkey关联时,删除Monkey

4.映射组成关系

4.1概念补充

  • 组成关系:部分类的对象被多个整体类的对象共享或部分只能属于特定整体。如手属于人,电视机和录像机共用一个遥控器。
  • 精粒度对象模型:对象模型(也称域模型)建立的目标是最大程度地提高代码的重用性。通过细化持久化类的粒度可提高代码可重用性,简化编程。

  • 粗粒度关系数据模型:建立关系数据模型的原则是在存在数据冗余的情况下,需要把粗粒度的表拆分成具有外键参照关系的几个细粒度的表,从而节省存储空间;在没有数据冗余的前提下,应该尽可能减少表的数目,简化表之间的参照关系,以便提高访问数据库的速度。图4-1展示了对象模型与关系模型的关系:

 图4-1 对象模型与关系模型的关系示例

说明:建立域模型和关系数据模型的原则不一样,使得持久化类的数目往往比数据库表的数目多,而且持久化类的属性并不和表的字段一一对应。

  • 值类型与实体类型

 HIbernate把持久化类的属性分为两种:值类型(Value)和实体(Entity)类型。

组件类型(如Address类)就是一种值类型,它具有如下特征:

  1. 没有OID,在数据库中没有对应的表;
  2. 不能被单独持久化,其生命周期依赖于所属的持久化对象的生命周期;
  3. 不需要单独的映射文件;
  4. 其他持久化类不允许关联此组件类(Adress);(这里缺少事实说明
  5. 组件类(Adress)可以关联其他的持久化类。

实体类型有OID,可以被单独持久化。

4.2 映射组成关系

Monkey使用<component>元素映射homeAddress属性,映射代码如下:

<component name="homeAddress" class="mypack.Address">
            <parent name="monkey" />
            <property name="province" type="string" column="HOME_PROVINCE"/>
            <property name="city" type="string" column="HOME_CITY"/>
            <property name="street" type="string" column="HOME_STREET"/>
            <property name="zipcode" type="string" column="HOME_ZIPCODE"/>
</component>
<component>有两个属性nameclass和两个子元素<parent><property>

4.3 映射复合组成关系

复合组成:一个Hibernate组件包含其他Hibernate组件或者和其他的实体类关联。如图4-2所示:

4-1 对象模型与关系模型的关系示例

其中,ComputerVendor为实体类。

Computer.hbm.xml中的复合组成关系的映射代码如下:

 <component name="cpuBox" class="mypack.CpuBox">
            <parent name="computer" />
            
            <property name="type" type="string" >
                <column name="CPUBOX_TYPE" />
            </property>
            
            <component name="graphicsCard" class="mypack.GraphicsCard">
               <parent name="cpuBox" />
              
               <property name="type" type="string" >
                  <column name="GRAPHICSCARD_TYPE" />
               </property>

            </component>

            <many-to-one                         <!--注意:这里允许组件类关联其他的持久化类-->
        		name="vendor"
        		column="CPUBOX_VENDOR_ID"
        		class="mypack.Vendor"
        		not-null="true" 
            />
    </component>
这里的<component>可以嵌套。

5.映射继承关系

5.1 概述

有如图5-1中的对象模型:

图5-1 包含继承关系的对象模型

此对象模型的实现及其中的持久化类的实现都是一样的,但可以有不同的映射方式,也就对应着不同的关系数据模型和映射文件。

三种映射继承关系的方式:

  • 继承关系树中的每个具体类对应一个表:关系数据模型完全不支持多态关联和多态查询。
  • 继承关系树中的根类对应一个表:对关系数据模型进行非常规设计,在数据表中加入额外的区分子表类型的字段。这种方式使得关系数据模型支持多态关联和多态查询,并且有最佳的查询性能。但和子类的属性对应的字段要满足允许为null的要求。(个人觉得是最佳实践)
  • 继承关系树的每个类对应一个表:常规设计,在关系数据模型中用外键参照关系来表示继承关系。查询性能不如第二种。

多态查询:在持久化层,利用”from Monkey“查询出所有的Monkey对象。

多态关联:在持久化层,加载的Team对象中monkeys集合中包含所有关联的Monkey对象。

注意:

以下介绍的三种方式中的Monkey类都定义为抽象类。

5.2 继承关系树中的每个具体类对应一个表

这里将Monkey定义为抽象类,没有创建MONKEYS数据表和Monkey.hbm.xml映射文件。

图5-2是每个具体类对应一个表:

图5-2 每个具体类对应一个表

图5-3是持久化类、映射文件和数据表之间的对应关系:

图5-3 持久化类、映射文件和数据表之间的对应关系

虽然Team类到Monkey类是多态关联的但关系数据库模型中没有描述Monkey和其子类的继承关系,所以无法映射Team类的Monkeys集合。这就导致:

  • 不支持多态查询

为检索所有的Monkey对象应分别检索JMonkey和CMonkey,然后合并到同一集合中。

  • 不支持多态关联

加载的Team对象中的monkeys集合中不包含任何的Monkey对象,需显示检索出所有的与Team对象关联的JMonkey和CMonkey对象然后加载到monkeys集合中。

  • 支持多态插入

如,save(monkey)时能根据monkey变量实际引用的实例类型插入数据。

5.3 继承关系树中的根类对应一个表

图5-4中继承关系树的根类对应一个表:

图5-4 继承关系树的根类对应一个表

图5-5 是持久化类、映射文件和数据表之间的对应关系:

图5-5 持久化类、映射文件和数据表之间的对应关系


Team类到Monkey类是多态关联的且关系数据库模型中可以描述Monkey和其子类的继承关系。

Team.hbm.xml核心映射代码:

<set 
        name="monkeys"
        inverse="true"
     >
        <key column="TEAM_ID" />
        <one-to-many class="mypack.Monkey" />
     </set> 
Monkey.hbm.xml核心映射代码:

<class name="mypack.Monkey" table="MONKEYS">    
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <discriminator column="MONKEY_TYPE" type="string"  />  <!--指定MONKEYS表中用于区分Monkey类型的字段。“JM”代表JMonkey,“CM”代表CMonkey-->
      <property name="name" type="string" column="NAME" />

      <many-to-one
        name="team"
        column="TEAM_ID"
        class="mypack.Team"
      />

      <subclass name="mypack.JMonkey" discriminator-value="JM" >
         <property name="color" column="COLOR" type="string" />
      </subclass>

      <subclass name="mypack.CMonkey" discriminator-value="CM" >
         <property name="length" column="LENGTH" type="double" />
      </subclass>
     
    </class>
当Monkey不是抽象类时,可以如下定义calss元素:

<class name="mypack.Monkey" table="MONKEYS" discriminator-value="MM">

5.3 继承关系树的每个类对应一个表

图5-6所示 继承关系树的每个类对应一个表

图5-6 继承关系树的每个类对应一个表

图5-7是 持久化类、映射文件和数据表之间的对应关系:

图5-7 持久化类、映射文件和数据表之间的对应关系

Team.hbm.xml中的映射代码与5.2节中的相同。

Monkey.hbm.xml核心映射代码如下:

 <class name="mypack.Monkey" table="MONKEYS">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <property name="name" type="string" column="NAME" />

      <many-to-one
        name="team"
        column="TEAM_ID"
        class="mypack.Team"
      />

      <joined-subclass name="mypack.JMonkey" table="JMONKEYS" >
         <key column="MONKEY_ID" />
         <property name="color" column="COLOR" type="string" />
      </joined-subclass>

      <joined-subclass name="mypack.CMonkey"  table="CMONKEYS" >
         <key column="MONKEY_ID" />
         <property name="length" column="LENGTH" type="double" />
      </joined-subclass>
     
    </class>

6.映射值类型集合

值类型集合(images)中存放的对象没有OID,且他们的生命周期依赖于集合所属的对象(Monkey)的生命周期。

  • java.util.Set:集合中对象无序且无重复。其实现TreeSet能对其排序。
  • java.uitl.List:集合中对象按索引位置排序,且可以有重复对象。
  • java.util.Map:集合中的每一个元素包含一对键对象和值对象,键对象无重复,值对象可重复。其实现TreeMap能对键对象排序。

Hibernate通过<set>、<idbag>、<list>和<map>元素可以将java集合映射到数据库。

注意:

1. <idbag>用来映射Bag集合(元素允许重复,但无特定顺序),而java中无Bag的接口,可在持久化类中用List来模拟。

2. Hibernate都提供了内置集合类封装了Java的集合类,当Session从数据库中加载Java集合时,会创建Hibernate内置集合的实例而不是java的集合实现类,这可以方便实现诸如集合代理、延迟检索、脏检查的功能。

3. 这里的集合值类型组件类值类型有区别。

6.1 映射Set

有如图6-1的表结构:

图6-1 MONKEYS表和IMAGES表结构

这里使用联合主键确保Monkey对象不允许有重复的照片文件名。

  • Monkey中的image属性:

private Set images=new HashSet();

  • Monkey.hbm.xml中映射images属性:

 <set   name="images"   table="IMAGES"    lazy="true" > <!--使用了延迟加载(默认),需使用Hibernate类的initialize()显示初始化images集合-->
        <key column="MONKEY_ID" />                      <!--IMAGES表的外键为MONKEY_ID-->
        <element column="FILENAME" type="string"  not-null="true"/>
   </set> 

6.2 映射Bag

图6-2显示了MONKEYS和IMAGES表结构:

图6-2  MONKEYS和IMAGES表结构

Bag包中的对象允许有重复,定义一个代理主键ID。

  • 用List模拟Bag,在Monkey中定义如下images属性:

private List images=new ArrayList();

  • Monkey.xml中映射images属性:

<idbag   name="images"   table="IMAGES"    lazy="true">
        <collection-id type="long" column="ID">
           <generator class="increment"/>
        </collection-id>
        <key column="MONKEY_ID" />
        <element column="FILENAME" type="string"  not-null="true"/>
   </idbag>   

6.3 映射List

图6-3显示了MONKEYS和IMAGES表结构:

图6-3  MONKEYS和IMAGES表结构

IMAGES表中多了一个位置索引字段POSITION,按位置排序(集合中元素有固定索引位置);MONKEY_ID和POSITION为联合主键,使得images集合可以存放重复对象。

  • Monkey中的images属性的定义方式同6.2,但用<list>映射:

private List images=new ArrayList();


  • Monkey.hbm.xml中映射images属性:

<list   name="images"   table="IMAGES"    lazy="true">
        <key column="MONKEY_ID" />
        <list-index column="POSITION" />  <!--设置代表索引的POSITION字段-->
        <element column="FILENAME" type="string"  not-null="true"/>
   </list>  

6.4 映射Map

图6-4显示了MONKEYS表和IMAGES表结构:

图6-4  MONKEYS表和IMAGES表结构

这里MONKEY_ID和IMAGE_NAME作为联合组件,使得对象不能有重复的键值。

  • Monkey中的images属性的定义:
private Map images=new HashMap();
  • Monkey.hbm.xml中映射images属性:
 <map   name="images"   table="IMAGES"    lazy="true">
        <key column="MONKEY_ID" />
        <map-key column="IMAGE_NAME" type="string"/>
        <element column="FILENAME" type="string"  not-null="true"/>
   </map>   

6.5 对集合排序

Hibernate对集合中的元素两种排序方式:
  • 数据库排序:Hibernate通过select到数据库中检索集合对象是,利用order by子句进行排序。
  • 内存排序:Hibernate把数据库中集合数据加载到内存中的Java集合后,利用Java的自然排序或客户化排序方式排序。

在映射文件中,Hibernate用sort属性设置内存排序,用order-by设置数据库排序。

图6-5显示了<set>、<idbag>、<list>、<map>的排序属性:

图6-5 <set>、<idbag>、<list>、<map>的排序属性



7.映射一对一关联关系

在映射组成关系时我们讨论了Monkey和Address类的组成关系,下面我们采用一对一的关联映射,当然如果从头设计对象模型和数据模型应优先考虑组成关系。映射一对一关系两种方式:
  • 按照外键映射:在MONKEYS表中定义两个外键HOME_ADDRESS_ID和COM_ADDRESS_ID,他们都参照ADDRESS表的主键。缺点:只能建立一个双向一对一关联,而另一个为单向一对一关联。
  • 按照主键映射:ADDRESS表的ID既是主键又是外键,参照MONKEYS表的主键。缺点:只有一个一对一关联,应优先考虑使用主键映射方式。

7.1 按照外键映射

如图7-1表关系:

图7-1  MONKEYS与ADDRESSES表结构

  • Monkey类中的homeAddress属性和comAddress属性定义:

    private Address homeAddress;
    private Address comAddress;
  • Address中的monkey属性定义:

    private Monkey monkey;

  • Monkey.hbm.xml中映射homeAddress和comAddress属性:

<many-to-one name="homeAddress" 
        class="mypack.Address"
        column="HOME_ADDRESS_ID"
        cascade="all"           <!--"all"表明保存更新或删除Monkey对象是会级联保存、更新、删除homeAddress-->
        unique="true"         <!--表明Monkey对象有唯一的一个homeAddress对象-->
    />

    <many-to-one name="comAddress" 
        class="mypack.Address"
        column="COM_ADDRESS_ID"
        cascade="all"
        unique="true"
    />

  • Address.hbm.xm中映射Monkey:

<one-to-one name="monkey" 
        class="mypack.Monkey"
       property-ref="homeAddress"   <!--表明建立homeAddress到Monkey对象的关联-->
    />
这里建立了Monkey和homeAddress对象之间的双向关联,而只有Monkey到comAddress的单向关联。(解决:把Address类定义为抽象类,HomeAddress和ComAddress为其子类,在HomeAddress.hbm.xml和ComAddress.hbm.xml中用<one-to-one>映射各自的属性monkey。但复杂对象模型变得复杂....)

7.2 按主键映射

假设Monkey类中只有一个address属性,如图7-2表结构:

图7-2 MONKEYS表和ADDRESSES表结构

MONKEYS表与ADDRESSES表共享主键。

  • Monkey.hbm.xml中映射address属性:

<one-to-one name="address" 
        class="mypack.Address"
        cascade="all" 
     />

  • Address.hbm.xml映射monkey属性:

 <class name="mypack.Address" table="ADDRESSES" >
    <id name="id" type="long" column="ID">
      <generator class="foreign">          <!--OID使用foreign生成策略保证Address对象与Monkey对象共享同一个OID-->
        <param name="property">monkey</param>
      </generator>
    </id>

   .......
<one-to-one name="monkey" 
        class="mypack.Monkey"
       constrained="true"   <!--ADDRESSES表的ID主键同时作为外键参照MONKEYS表-->
    />

8.映射多对多关联关系

8.1 映射单向多对多关联关系

如图8-1表关系:

图8-1 MONKEYS、TEACHERS及连接表的结构

建立Monkey到Teacher的单向多对多关系:

  • Monkey中的teachers属性定义:

private Set teachers=new HashSet();

  • Monkey.hbm.xml映射teachers属性:

  <set name="teachers" table="LEARNING"
        lazy="true"
        cascade="save-update">       <!--多对多应将cascade属性设置成“save-update”-->
        <key column="MONKEY_ID" /> 
        <many-to-many class="mypack.Teacher" column="TEACHER_ID" />
    </set>

8.2 映射双向多对多关联关系

Monkey类与Teacher三种映射方式实现多对多关联:

  • 两端都用<set>,其中一端的inverse属性为true。
  • 定义专门的组件类Learning来描述关系,适合关联包含属性的情形。
  • 分解多对多关系为Monkey与Learning,及Teacher与Learning类的两个一对多关系。(最佳实践:可以使对象模型和关系模型具有更好的可扩展性)
8.2.1 关联两端使用<set>
  • Monkey类中定义teachers属性:

 private Set teachers=new HashSet();

  • Teacher类中定义monkeys属性:

 private Set monkeys=new HashSet();

  • Monkey.hbm.xml映射teachers属性:

 <set name="teachers" table="LEARNING"
        lazy="true"
        cascade="save-update">
        <key column="MONKEY_ID" />
        <many-to-many class="mypack.Teacher" column="TEACHER_ID" />
    </set>
 


  • Teacher.hbm.xml映射monkeys属性:

<set name="monkeys" table="LEARNING"
        lazy="true"
        inverse="true"
        cascade="save-update">
        <key column="TEACHER_ID" />
        <many-to-many class="mypack.Monkey" column="MONKEY_ID" />
    </set>
8.2.2 使用组件类集合

如图8-2表结构:

图8-2 MONKEYS、TEACHERS及连接表的结构

首先编写组件类Learning。

  • Monkey类和Teacher都定义了Set类型的learnings属性:

private Set learnings=new HashSet();
  •  Monkey.hbm.xml映射learnings:
 <set name="learnings" lazy="true" table="LEARNING" >
        <key column="MONKEY_ID" />
        <composite-element class="mypack.Learning" >
          <parent name="monkey" />
          <many-to-one name="teacher" class="mypack.Teacher" column="TEACHER_ID" not-null="true"/>
          <property name="gongfu" column="GONGFU" type="string" not-null="true" />
         </composite-element> 
    </set>
  • Teacher.hbm.xml映射learnings:

 <set name="learnings" lazy="true" inverse="true" table="LEARNING" >
        <key column="TEACHER_ID" />
        <composite-element class="mypack.Learning" >
          <parent name="teacher" />
          <many-to-one name="monkey" class="mypack.Monkey" column="MONKEY_ID" not-null="true"/>
          <property name="gongfu" column="GONGFU" type="string" not-null="true" />
         </composite-element> 
    </set>

8.2.3 把多对一关联分解为两个一对多关联

如图8-3表结构:

图8-3 MONKEYS、TEACHERS及连接表的结构

这里Learning是实体类。

  • Monkey类和Teacher都定义了Set类型的learnings属性:

 private Set learnings=new HashSet();
  • Learning定义了monkey和teacher属性:

    private Teacher teacher;
    private Monkey monkey;

  • Monkey.hbm.xml映射learnings:

 <set name="learnings" lazy="true" inverse="true" cascade="save-update">
        <key column="MONKEY_ID" />
        <one-to-many  class="mypack.Learning" />
   </set>

  • Teacher.hbm.xml映射learnings:

 <set name="learnings" lazy="true" inverse="true" cascade="save-update">
        <key column="TEACHER_ID" />
        <one-to-many  class="mypack.Learning" />
     </set>

  • Learning.hbm.xml映射monkey和teacher属性:

 <class name="mypack.Learning" table="LEARNING" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="gongfu" column="GONGFU" type="string" />
    
    <many-to-one name="monkey" column="MONKEY_ID" class="mypack.Monkey" not-null="true" />
    <many-to-one name="teacher" column="TEACHER_ID" class="mypack.Teacher" not-null="true" />

 
  </class>

<这是测试目录生成的BUG>

9.总结

处理映射关系从四个方面把握:

  • 在持久化类中体现出雷雨类之间的特定关系;
  • 数据表与持久化类对应;
  • 创建对象-关系映射文件;
  • 通过Hibernate API操纵具有特定关系的多个对象。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值