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的 |
这种设计方式完全符合关系模型的设计原则,而且不存在冗余 |
可维护性 |
如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改 |
维护起来比较方便,只需要修改一张表 |
维护起来比较方便,对每个类的修改只需要修改其所对应的表 |
灵活性 |
映射的灵活性很大,子类可以对包括基类属性在内的每一个属性进行单独的配置 |
灵活性差,表中的冗余字段会随着子类的增多而增加 |
灵活性很好,完全是参照对象继承的方式进行映射配置 |
查询的性能 |
对于子类的查询只需要访问单独的表,但对于父类的查询则需要检索所有的表 |
在任何情况下的查询都只需处理这一张表 |
对于父类的查询需要使用左外连接,而对于子类的查询则需要进行内连接 |
维护的性能 |
对于单个对象的持久化操作只需要处理一个表 |
对于单个对象的持久化操作只需处理一个表 |
对于子类的持久化操作至少需要处理两个表 |
三种继承映射方式的比较
分享到:
相关推荐
在软件开发领域,尤其是使用ORM(对象关系映射)技术进行数据库操作时,“继承映射”是一个关键的概念。它允许在数据库中表示面向对象编程中的继承关系,即一个子类可以继承父类的所有属性和方法。这种映射方式极大...
本主题将深入探讨"Hibernate继承映射+C3P0代码"的相关知识点。 首先,让我们理解Hibernate的继承映射。在Java中,我们可以创建一个基类,然后派生出多个子类,这种设计模式在数据库中也可以被映射出来。Hibernate...
本教程主要探讨的是Hibernate中的“继承映射”特性,这是一项关键功能,它允许我们将复杂的类继承结构映射到数据库表中。通过继承映射,我们可以有效地管理和组织数据,提高代码的复用性和可维护性。 在Hibernate中...
继承映射则适用于具有共同属性但又有所区别的实体,如不同类型的用户、不同状态的订单等,通过继承关系可以避免代码重复,提高代码复用性。 总结,JPA提供了强大的关联和继承映射机制,让开发者能更便捷地处理...
Hibernate继承映射是将Java类的继承关系映射到数据库表的一种策略,使得对象模型的复杂性能够平滑地转化为关系数据库模型。本篇将详细介绍Hibernate继承映射的第一种策略——每棵类继承树对应一张表,即单一表继承...
映射继承关系是Hibernate中一项高级特性,它允许你将面向对象的设计模式映射到关系型数据库中。选择正确的映射策略取决于许多因素,包括性能需求、数据一致性和应用程序架构。通过了解这些不同的映射策略,你可以更...
《Hibernate继承映射详解》 Hibernate,作为Java领域中的一款著名对象关系映射(ORM)框架,极大地简化了数据库操作。在实际项目中,我们常常会遇到类的继承关系,而Hibernate提供了强大的支持来处理这种继承关系的...
《Hibernate继承映射详解》 在Java开发中,对象关系映射(ORM)框架如Hibernate大大简化了数据库操作。Hibernate不仅提供了对基本数据类型的映射,还支持复杂的数据结构,如继承关系的映射。本篇文章将深入探讨...
内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。 ORM 技术包括...
总之,Hibernate的继承映射功能,尤其是通过注解的方式,极大地简化了Java对象与数据库表之间的映射过程。联合继承策略适用于复杂的继承结构,但需要根据具体需求权衡性能和设计复杂性。在实际项目中,应结合具体...
在本教程中,我们将深入探讨Hibernate中的继承映射,特别是在"Hibernate教程17_继承映射_补充2"中所涉及的主题。Hibernate是Java中一个非常流行的对象关系映射(ORM)框架,它允许开发者用面向对象的方式处理数据库...
4. **继承映射的配置**:在Hibernate的XML映射文件或注解中,需要显式声明继承关系。例如,使用`@Inheritance(strategy=InheritanceType.SINGLE_TABLE)`注解在父类上,然后在子类上使用`@DiscriminatorValue`指定...
在本教程中,我们将深入探讨Hibernate中的继承映射策略,特别是"Table Per Class"策略,这是Java对象模型到关系数据库映射的一种方法。在Hibernate框架中,继承是通过ORM(对象关系映射)来实现的,它允许我们将复杂...
总的来说,iBATIS的继承映射利用`discriminator`列实现了对象的多态性,使得我们可以根据数据库中的信息动态地实例化合适的Java对象。这种设计大大简化了处理复杂数据库结构的代码,提高了代码的可读性和可维护性。...
### Hibernate的继承多态映射关系详解 在软件开发领域,特别是使用面向对象编程语言如Java进行开发时,我们经常需要处理复杂的类继承关系。在ORM(Object-Relational Mapping)框架如Hibernate中,如何优雅地将这些...
本篇主要探讨的是Hibernate中的继承映射策略,特别是“每个子类一张表”(Table per subclass)的方式。这种方式也被称为单表继承或多表继承,是Hibernate支持的四种继承映射策略之一。了解并熟练掌握这种映射模式...
2. **创建映射配置**:定义一个继承自`MapperProfile`的类,并在其中使用` CreateMap`方法来指定源对象类型和目标对象类型。 ```csharp public class MyMappingProfile : MapperProfile { public ...