`
sqe_james
  • 浏览: 262089 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

对象继承的映射

    博客分类:
  • J2EE
阅读更多

Hibernate支持三种继承映射策略:

  • 每个具体类一张表(table per concrete class) 将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系开数据模型中考虑域模型中的继承关系和多态。
  • 每个类分层结构一张表 (table per class hierarchy) 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
  • 每个一张表(table per subclass) 域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。

1.每个具体类一张表

把域模型中的每个实体对象类映射到一个单独的表中,这是最简单的映射方式。对过这种方式将域模型映射为关系模型两个步骤

  • 为每个对象建立一个单独的表。
  • 根据域模型中实体对象间的关联关系和聚合关系建立表之间的关联关系。这种关联关系是通过外键来实现的。

在使用这种方法实现域模型到关系开模型之间的转换时需要注意,在这个转换策略中,并没有单独处理对象之间的继承关系,而是通过不同的表来分别实现这些实体对象。这也就造成了这种映射方法并不能真正完全体现对象之间的关系。


对于使用每个具体类一张表的映射策略, 在创建 Hibernate 映射配置文件的时候也有两种配置方法可以使用。

 

其中一种配置方法是使用,如下所示:  

<class name="Payment">
  <id name="id" type="long" column="PAYMENT_ID">
    <generator class="sequence"/>
  </id>
  <property name="amount" column="AMOUNT"/>
    ...

  <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
    <property name="creditCardType" column="CCTYPE"/>
    ...
  </union-subclass>
 
  <union-subclass name="CashPayment" table="CASH_PAYMENT">
    ...
  </union-subclass>

  <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
    ...
  </union-subclass>
</class>

使用这种方式除了每个子类对应一个表外,其定义方式与Java对象的继承非常相似。也就是子类可以继承在父类中公共的属性定义,但在这里需要注意, 使用这种方式进行Java对象的映射配置必须要保证在超类中定义这些属性,在所有的表中所映射的字段的名字都必须相同。


如果采用另外一种方法来建立对象的映射文件,则可以弥补这方面的不足,但又会带来其他问题。在这种方法中,没有定义类之间的映射关系,而是用三个独立的class元素来描述这些对象的映射方法,如下所示:

<class name="CreditCardPayment" table="CREDIT_PAYMENT">  
  <id name="id" type="long" column="CREDIT_PAYMENT_ID">  
    <generator class="native"/>  
  </id>
  <property name="amount" column="CREDIT_AMOUNT"/>  
    ...  
</class>  
   
<class name="CashPayment" table="CASH_PAYMENT">  
  <id name="id" type="long" column="CASH_PAYMENT_ID">  
     <generator class="native"/>  
  </id>  
  <property name="amount" column="CASH_AMOUNT"/>  
    ...  
</class>  
   
<class name="ChequePayment" table="CHEQUE_PAYMENT">  
  <id name="id" type="long" column="CHEQUE_PAYMENT_ID">  
    <generator class="native"/>  
  </id>  
  <property name="amount" column="CHEQUE_AMOUNT"/>  
   ...  
</class>  

可以看到,采用这种独立映射方式的配置方法,在配置文件中没有定义这些类之间的任何关系。也就是说,三个类都是独立存在的。使用这种映射方式解决了相同属性必须使用相同字段名的限制,但又带来了另外一个问题,就是从父类继承的属性需要在每个子类中都进行相应的定义,造成属性配置的重复。

 

2.每个类分层结构一张表

采用这种方式的特点是需要为每个类分层建立一个表,也就是说依据继承层次的结构来确定建立表的数量。如下所示:

<class name="Payment" table="PAYMENT">  
  <id name="id" type="long" column="PAYMENT_ID">  
    <generator class="native"/>  
  </id>  
  <discriminator column="PAYMENT_TYPE" type="string"/>  
  <property name="amount" column="AMOUNT"/>  
    ...  
  <subclass name="CreditCardPayment" discriminator-value="CREDIT">  
    <property name="creditCardType" column="CCTYPE"/>  
         ...  
  </subclass>  
  <subclass name="CashPayment" discriminator-value="CASH">  
    ...  
  </subclass>  
  <subclass name="ChequePayment" discriminator-value="CHEQUE">  
    ...  
  </subclass>  
</class>

通过以上清单可以看出,这里的映射只需要一张表就可以完成所有实体对象的映射。这要求这个表必须具有与所有的映射对象的属性相对的字段,而在这里就存在一个很大的限制,也就是某个子类特有的属性所映射的字段不能设置非空属性,否则在进行其他子类的持久化的时候会产生异常。



采用这种映射方式需要注意的是它通过增加一个字段(在这里是 PAYMENT_TYPE 字段)来标识某个记录是属于哪个实体对象的。通过标签中的定义可以看出,如果该值为 CREDIT ,则表示这个记录是 CreditCardPayment 对象的持久化数据。如果该值为 CASH 则表示该记录是 CashPayment 对象的持久化数据。


优点: 采用这种映射方式在执行对象检索的时候可以减少查询语句的执行次数。

 

3.每个子类一张表

和每个具体类一张表的映射策略区别在于每个具体类一张表的映射策略所建立的表是独立的,每个表都包括了子类所自定义的属性和由父类所继承的属性的映射字段。而采用每个子类一张表的映射策略时,子类所对应的表只包括所定义的属性,而子类所对应的表与父类所对应的表是通过外键来进行关联的。


使用这种映射策略的好处是父类所定义的属性就在父类的表中进行映射,而子类所定义的属性就在子类的表中进行映射。避免了子类所定义的表中仍然需要定义父类属性的映射 字段所带来的麻烦。如下示例:

<class name="Payment" table="PAYMENT">  
  <id name="id" type="long" column="PAYMENT_ID">  
    <generator class="native"/>  
  </id>  
  <property name="amount" column="AMOUNT"/>  
    ...  
  <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">  
    <key column="PAYMENT_ID"/>  
      ...  
  </joined-subclass>
 
  <joined-subclass name="CashPayment" table="CASH_PAYMENT">  
    <key column="PAYMENT_ID"/>  
    <property name="creditCardType" column="CCTYPE"/>  
      ...  
  </joined-subclass>
 
  <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">  
    <key column="PAYMENT_ID"/>  
      ...  
  </joined-subclass>  
</class>

通过上面的配置文件可以看出,采用每个子类一张表的映射方式可以在最大程度上“模拟”面向对象的继承行为,通过一个外键字段将父表和子表进行关联。同时也避免了前面两种方式所带来的结构冗余的情况。



注意,对“每个子类一张表”的映射策略,Hibernate 的实现不需要辨别字段,而其他 的对象/关系映射工具使用了一种不同于 Hibernate 的实现方法,该方法要求在超类 表中有一个类型辨别字段(type discriminator column)Hibernate 采用的方法更 难实现,但从关系(数据库)的角度来看,按理说它更正确。若你愿意使用带有辨别字 段的“每个子类一张表”的策略,你可以结合使用 与,如下所示:

<class name="Payment" table="PAYMENT">  
  <id name="id" type="long" column="PAYMENT_ID">  
    <generator class="native"/>  
  </id>  
  <discriminator column="PAYMENT_TYPE" type="string"/>  
  <property name="amount" column="AMOUNT"/>  
    ...  
  <subclass name="CreditCardPayment" discriminator-value="CREDIT">  
    <join table="CREDIT_PAYMENT">  
      <key column="PAYMENT_ID"/>  
      <property name="creditCardType" column="CCTYPE"/>  
      ...  
    </join>  
  </subclass>
 
  <subclass name="CashPayment" discriminator-value="CASH">  
    <join table="CASH_PAYMENT">  
      <key column="PAYMENT_ID"/>  
      ...  
    </join>  
  </subclass>

  <subclass name="ChequePayment" discriminator-value="CHEQUE">  
    <join table="CHEQUE_PAYMENT" fetch="select">  
      <key column="PAYMENT_ID"/>  
      ...  
    </join>  
  </subclass>
</class>

可选的声明fetch="select" ,是用来告诉 Hibernate ,在查询超类时, 不要使用外部连接(outer join) 来抓取子类 ChequePayment 的数据。

 

 

4.对象继承的映射方法总结

 

三种继承映射方式的比较

比较方面

每个具体类一张表

每个类分层结构一张表

每个子类一张表

建立关系模型的原则 每个具体类对应 一张表,有多少具体类就需要建立多少个独立的表 描述一个继承关系只用一张表 每个子类使用一张表。但这些子类所对应的表都关联到基类所对应的表中
关系模型的优缺点 这种设计方式符合关系模型的设计原则,但有表中存在重复字段的问题 缺点有二:首先表中引入了区分子类的字段。其次,如果某个子类的某个属性的值不能为空,那么在数据库一级是不能设置该字段为NOT NULL的 这种设计方式完全符合关系模型的设计原则,而且不存在冗余
可维护性 如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改 维护起来比较方便,只需要修改一张表 维护起来比较方便,对每个类的修改只需要修改其所对应的表
灵活性 映射的灵活性很大,子类可以对包括基类属性在内的每一个属性进行单独的配置 灵活性差,表中的冗余字段会随着子类的增多而增加 灵活性很好,完全是参照对象继承的方式进行映射配置
查询的性能 对于子类的查询只需要访问单独的表,但对于父类的查询则需要检索所有的表 在任何情况下的查询都只需处理这一张表 对于父类的查询需要使用左外连接,而对于子类的查询则需要进行内连接
维护的性能 对于单个对象的持久化操作只需要处理一个表 对于单个对象的持久化操作只需处理一个表 对于子类的持久化操作至少需要处理两个表

 

分享到:
评论
1 楼 ylzyd12345 2009-01-09  
    帮助颇大~ 谢谢, 别人不回复可以.俺要回

相关推荐

    HarmonyOS之实现对象关系映射数据库的升级、备份、删除、恢复以及表的增删改查.zip

    本示例通过注解和继承来实现数据库和表的创建,实现了数据库的升级、备份、删除、恢复,实现了表的增删改查,并监听数据变化。 @Database注解,且继承了OrmDatabase的类,对应关系型数据库; @Entity注解,且继承了...

    基于Hibernate的对象关系映射研究

    本文分析了基于Hibernate框架的两种对象关系映射策略,并比较了三种继承映射策略的优缺点,设计了一种基于Hibernate的ORM持久化层的系统架构,该架构结构清晰、开发效率高,具有较高的应用价值。

    LLModel:JSON 的对象属性映射器

    LLModel:JSON 对象属性映射器(已弃用,不再维护) LLModel 是一个用于将 JSON 数据映射到对象属性的库。 它与一起工作得很好。 LL型号: 支持递归模型初始化(见下面的例子) 支持原始值,例如 bool、char、...

    Hibernate映射继承关系的三种方案.docx

    对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。hibernate的集成映射可以理解为持久化类之间的继承关系。在上边的例子中,学生集成了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的...

    业务对象到关系数据库映射的若干模式

    摘要这些模式描述如何把业务对象映射到非面向对象的数据库中。面向对象和非面向对象这两种技术存在着阻抗不匹配(impedancemismatch),因为对象由数据和行为组成,而一个关系型数据库则是由表和它们之间的关系组成...

    XLYMapping:在本地对象中映射 JSON 的映射系统

    目标对象可以是从 NSObject 继承的对象,因为我使用 KVC 来设置值。 更多细节显示在下面的演示和测试代码中。注意:映射过程如下: 将映射。 有机会修改 JSON。 动态地图。 更改以提供另一个映射。 创建目标对象。 ...

    SQL Artisan数据库访问组件功能概述

    包括:表对象支持数据操作,对象继承,视图对象映射,统计对象映射等.为了让组件功 能扩展更方便,把组件的数据映射方式进行重构,由原来的XML描述改成Attribute;并把相关应映射成员搬迁到 HFSoft.Data.Mapping名称空间下....

    CRL面向对象ORM开发框架

    通过业务对象封装继承,实现业务重用性,比较常用的封装有,会员/账户系统,字典配置,分类系统,在线支付,订单/购物车,权限验证/菜单系统等等,当然也可以写自已的业务封装 效率问题:在对象映射上作了缓存处理,查询效率...

    将关系数据映射到业务实体(转)

    学习向 Microsoft .NET 应用程序公开数据的最佳方式,以及如何实现一个有效的策略以便在分布式应用程序的层间传递数据。(本文包含一些指向英文站点的链接。)

    iguana:对象文档映射器(ODM)用于角度

    对象文档映射器(ODM)用于角度 鬣蜥是用于角度的对象文档映射器。 它当前的版本为0.0.30,并且还有很长的路要走。 当前功能: 单一集合继承(多态) -在单个集合中将不同的类分配给不同的文档。 嵌入式文档-将类...

    面向对象的类测试方法研究

    类,从基于基本路径测试的结构测试的视角、面向对象的继承映射的视角、类的成员函数与数据成员之间交互作用 的视角来检查类中的错误,得出了从不同的视角测试相同的类可以检查出类的不同错误的结论,通过实例阐述这 些...

    JPA详解视频教程 第19讲 映射关联和继承.avi

    JPA用于整合现有的ORM技术,可以简化现有Java EE和Java SE应用对象持久化的开发工作,实现ORM的统一。JPA详解视频教程 第19讲 映射关联和继承.avi

    CrystDB:CrystDB是基于SQLite的线程安全且方便的对象关系映射数据库

    CrystDB是基于SQLite的线程安全且方便的对象关系映射数据库。 它轻巧高效。 当处理简单数据对象时,它具有处理速度,特别是在查询和存储操作方面。 它是Realm和Core Data的绝佳替代品。 产品特点 轻量级:源文件更少...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     11.1.3 Java大对象类型的Hibernate映射类型  11.1.4 JDK自带的个别Java类的Hibernate映射类型  11.1.5 使用Hibernate内置映射类型  11.2 客户化映射类型  11.2.1 用客户化映射类型取代Hibernate组件  11.2.2 ...

    c# 反射获取传入对象的属性拼接sql语句实现增、删、改、查

    利用反射动态拼接sql。 daohelper属于DAL层,objectdata类属于BLL层,BLL层引用DAL层。映射数据的表继承objectdata类。例如,数据表book,根据字段与属性一一对应的方式创建book类,插入数据库时,直接book.save()

    VC设计模式之消息映射

    主要是通过一个基类来定义一个公用接口,派生类动态实现此接口,派生类对象用基类的构造函数来记录,消息传送时,可以是每个派生类对象分开,通过一个messageoperate来管理消息的传送,这样消息映射机制更加灵活。...

    3-JavaScript高级教程-面相对象程序设计.pptx

    对象的每个属性或方法都有一个名字,而每个名字都映射 到一个值。正因为这样(以及其他将要讨论的原因).我们可以把ECMAScript的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数。 每个对象都是基于一...

    neomodel:Neo4j 图数据库的对象图映射器 (OGM)

    一个用于图形数据库的对象图映射器(OGM),建立在很棒的熟悉的基于类的模型定义具有适当的继承性。 强大的查询API。 通过基数限制强制执行架构。 全面的交易支持。 线程安全。 前/后保存/删除挂钩。 通过Django ...

    C++基础入门:面相对象编程C++中的封装、继承和多态.docx

    面向对象编程(Object-Oriented Programming,简称OOP)是一种软件开发方法,它将现实世界的概念和对象映射到程序设计中。C++作为一种强大的编程语言,提供了丰富的面向对象编程特性,其中封装、继承和多态是最重要...

Global site tag (gtag.js) - Google Analytics