本文翻译自NHibernate官方文档NHibernate Reference Documentation 4.1

受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助。

侵删。

关于继承映射的三个继承映射方案

NHibernate支持三个基本的继承映射隐射方案。

    • 一个继承一张表(table per class hierarchy)

    • 一个子类额外信息一张表(table per subclass)

    • 一个子类全部信息一张表(table per concrete class)

NHibernate还支持第四种,比较特殊的一种多态:

    • 隐式多态(implicit polymorphism)

针对不同的继承结构,我们可以使用不同的映射方案,然后使用隐式多态去获得整个继承关系中的多态属性。然而NHibernate不支持在一个<class>标签下面混合使用<subclass>,<joined-subclass>和<union-subclass>三种映射。然而,通过使用<subclass>和<join>标签,NHibernate支持将一个继承一张表(table per hierarchy )和一个子类额外信息一张表(table per subclass)两种映射方案混合在同一个<class>标签下面使用(见下文)。

NHibernate也支持将subclass,union-subclass和joined-subclass的mapping分散在不同文件中,我们可以直接在各个文件的<hibernate-mapping>标签中定义类的mapping。这样就可以让你能够通过增加mapping文件来扩展整个类的层级结构。当然你必须在子类的mapping文件中设置extends属性来指向它的父类。

 <hibernate-mapping>
<subclass name="DomesticCat" extends="Cat" discriminator-value="D">
<property name="name" type="string"/>
</subclass>
</hibernate-mapping>

一个继承一张表(table per class hierarchy)

假设我们有一个IPayment接口,有CreditCardPayment, CashPayment,ChequePayment三种实现方式。这种一个继承一张表的配置是这样:

<class name="IPayment" table="PAYMENT">
<id name="Id" type="Int64" column="PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="String"/>
<property name="Amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
...
</subclass>
<subclass name="CashPayment" discriminator-value="CASH">
...
</subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE">
...
</subclass>
</class>

只需要一张表就可以了,但是这种方式有一个局限性:子类对应的列不能有NOT NULL的限制。

一个子类额外信息一张表(table per subclass)

一个一个子类额外信息一张表的配置是这样:

<class name="IPayment" table="PAYMENT">
<id name="Id" type="Int64" 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"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
</class>

这种配置方式需要四张表。三张字表的主键和父表关联(他们之间的关系实际上是一对一关系)。

一个子类全部信息一张表(table per concrete class),使用一个区分字段

我们注意到,在NHibernate中,一个子类额外信息一张表(table per subclass)的实现方式不需要区分字段,其他的实体/关系映射工具使用了一种不同的实现方式:他们的父表设置了一个区分类型的字段。NHibernate使用了一种更麻烦但是关系描述角度来看更加准确的的实现方式。如果你想在一个子类额外信息一张表的方式上实现区分字段,你需要把<subclass>和<join>标签结合起来使用如下:

<class name="Payment" table="PAYMENT">
<id name="Id" type="Int64" 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"的声明告诉NHibernate在查询的时候不要使用outer join获得ChequePayment的子类。

父类信息和子类信息混合在同一张表内(Mixing table per class hierarchy with table per subclass)

你甚至可以将一个继承一张表(table per class hierarchy)和一个子类额外信息一张表(table per subclass)两种方式结合:

<class name="Payment" table="PAYMENT">
<id name="Id" type="Int64" 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">
<property name="CreditCardType" column="CCTYPE"/>
...
</join>
</subclass>
<subclass name="CashPayment" discriminator-value="CASH">
...
</subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE">
...
</subclass>
</class>

对于这些mapping的方式,要使用<many-to-one>映射一个IPayment的多态连接。

<many-to-one name="Payment" column="PAYMENT" class="IPayment"/>

一个子类全部信息一张表(table per concrete class)

有两种方式可以实现,第一种方式是使用<union-subclass>

<class name="Payment">
<id name="Id" type="Int64" 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>

三个类分别表示三个表,每个表都定义了类的所有属性,也包括继承过来的属性。

这种方式的缺点在于如果属性继承自父类,那么列名在子类中必须完全一样。(我们可能在将来的版本中解决这个问题)序列的生成方式不能独立,主键种子(primary key seed)不许在所有union的子类中共用。

如果你的父类是abstract,就需要设置abstract="true"。当然,如果它不是abstract的,那么久需要一个额外的表(就像上面的一个继承一张表例子那样)来装父类的实例。

一个子类全部信息一张表,使用隐式多态(Table per concrete class, using implicit polymorphism)

另外的一个方式是使用隐式多态:

<class name="CreditCardPayment" table="CREDIT_PAYMENT">
<id name="Id" type="Int64" 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="Int64" 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="Int64" column="CHEQUE_PAYMENT_ID">
<generator class="native"/>
</id>
<property name="Amount" column="CHEQUE_AMOUNT"/>
...
</class>

我们可以注意到,我们不必要显示地声明IPayment接口。同时,我们也可以发现IPayment接口被映射到了在各个具体实现类上面了。如果你想要避免重复,可以考虑使用XML实体(例如,在mapping文件的DOCTYPE声明和&allproperties中[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] )

这种方式的缺点在于NHibernate在执行多态查询的时候不会产生SQL Union语句。

<any name="Payment" meta-type="string" id-type="Int64">
<meta-value value="CREDIT" class="CreditCardPayment"/>
<meta-value value="CASH" class="CashPayment"/>
<meta-value value="CHEQUE" class="ChequePayment"/>
<column name="PAYMENT_CLASS"/>
<column name="PAYMENT_ID"/>
</any>

隐射多态混合其他的继承映射(Mixing implicit polymorphism with other inheritance mappings)

关于隐式多态还有一个需要注意的地方。因为子类的映射在各自的<class>标签之中配置(因为IPayment只是一个接口),每一个子类又有可能是其他的table-per-class或者table-per-subclass继承结构中的一员!(当然你可以继续使用IPayment的多态查询)

<class name="CreditCardPayment" table="CREDIT_PAYMENT">
<id name="Id" type="Int64" column="CREDIT_PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="CREDIT_CARD" type="String"/>
<property name="Amount" column="CREDIT_AMOUNT"/>
...
<subclass name="MasterCardPayment" discriminator-value="MDC"/>
<subclass name="VisaPayment" discriminator-value="VISA"/>
</class> <class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
<id name="Id" type="Int64" column="TXN_ID">
<generator class="native"/>
</id>
...
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="Amount" column="CASH_AMOUNT"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="Amount" column="CHEQUE_AMOUNT"/>
...
</joined-subclass>
</class>

和上面的例子一样,我们仍然不需要显示声明IPayment接口。如果我们查询了一个IPayment接口的一个实例——例如,from IPayment——NHibernate就会自动返回CreditCardPayment(和它的子类,因为他们也实现了IPayment接口),CashPayment和ChequePayment的实例,但是不会返回NonelectronicTransaction的实例。

局限性

对于实现“隐式多态”的“一个子类全部信息一张表”方式,存在一些局限。如果使用<union-subclass>映射方式相对会少一些限制。

以下表格展示了NHibernate中一个子类全部信息一张表和隐式多态的映射方式的限制情况。

表格 继承映射的一些特性

继承类型 多对一的多态 一对一的多态 一对多的多态 多对多的多态 多态的load()/get() 多态查询 多态连接 外连接fetching的支持情况
一个继承一张表(table per class-hierarchy) <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
一个子类额外信息一张表(table per subclass) <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
一个子类全部信息一张表(table per concrete-class (union-subclass)) <many-to-one> <one-to-one> <one-to-many>(for inverse="true"only) <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
一个子类全部信息一张表(table per concrete class (implicit polymorphism)) <any>

not supported

not supported <many-to-many> use a query from IPayment p


not supported

not supported

NHibernate官方文档——第八章 继承映射(Inheritance Mapping)的更多相关文章

  1. NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)

    映射声明 对象/关系映射在XML文件中配置.mapping文件这样设计是为了使它可读性强并且可修改.mapping语言是以对象为中心,意味着mapping是围绕着持久化类声明来建立的,而不是围绕数据表 ...

  2. NHibernate官方文档中文版--ISessionFactory的配置(ISessionFactory Configuration)

    由于NHibernate是被设计应用在许多不同环境中的,因此它存在很多配置参数.幸运的是,这些参数大多都有合理的默认值,而且NHibernate发布的时候伴随着一个App.config 例子(可在sr ...

  3. NHibernate官方文档中文版——批量插入(Batch inserts)

    A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this: 一 ...

  4. NHibernate官方文档中文版--只读实体类型(Read-only entities)

    重点 NHIbernate处理只读对象的方式可能和你在别处看到的不同.不正确的使用方式可能造成不可预料的结果. 当一个实体是只读的时候: NHIbernate不会对实体的简单属性和单向关联数据检查数据 ...

  5. NHibernate官方文档中文版——事务和并发(Transactions And Concurrency)

    NHibernate本身并不是一个数据库.它是一个轻量级的对象-关系映射工具.因此,它的事务管理代理给对应的数据库连接.如果这个连接代理了一个分布式的事务,ISession管理的操作就会自动成为整个分 ...

  6. NHibernate官方文档中文版-框架架构(Architecture)

    总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ...

  7. NHibernate官方文档中文版——持久化类(Persistent Classes)

    持久化类是一个应用程序中的类,主要用来实现业务逻辑(例如,在电商应用中的客户和订单类).持久化类,就像它的名字一样,生命周期短暂并且用来持久化的据库对象实例. 如果这些类的构造能够依照一些简单的原则, ...

  8. NHibernate官方文档中文版--拦截器和事件(Interceptors and events)

    对于应用程序来说,能够对NHibernate内部发生的事件做出响应式很有用的.这能够有助于实现一些类的功能或者扩展NHibernate的功能. 拦截器 IInterceptor接口提供了应用程序ses ...

  9. OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)

    OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...

随机推荐

  1. 在Struts2 Action中快速简便的访问Request、Session等变量

    前言——正常情况下如何在Action中获取到这些变量 全部方法(共四种)可以参考:http://blog.csdn.net/itmyhome1990/article/details/7019476 这 ...

  2. 【linux】如何解决VMWare上linux虚拟机连不上外网的问题?

    >>>故障现象:虚拟机连接不到外网? >>>故障背景: Centos7.4发行版本: 虚拟机和VM软件都是nat模式: 注意这里默认的VMWare的DHCP服务时开 ...

  3. 初识MVC框架

    MVC框架 是一个框架模式,它使应用程序的输入.处理和输出分开.它可以使业务逻辑.数据.界面显示分离,使得耦合度大大降低,在这一方面与"三层"思想类似.      M--Model ...

  4. EXTJS4.0 显示图片 动态图片

    在网上找了好久没有好的解决方法 都是用 'box' 什么的组件 改写的 autoEl 好麻烦,修改 好的属性都不能用.弄了好久没弄成 最后: 用panel  显示 html 文本 追加 ‘'<i ...

  5. log4net配置,正在用

    <?xml version="1.0" encoding="utf-8" ?> <log4net> <appender name= ...

  6. 行为型设计模式之命令模式(Command)

    结构 意图 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 适用性 抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(c a ...

  7. artDialog组件与iframe

    背景 组件官网. 未用过的朋友可以先了解下. 当Content参数传递html元素时,官方的解释是: 备注:1.元素不是复制而是完整移动到对话框中,所以原有的事件与属性都将会保留 2.如果隐藏元素被传 ...

  8. BZOJ1588 [HNOI2002]营业额统计 splay模板

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 16189  Solved: 6482 [Submit][S ...

  9. MVC5 WebAPI 跨域处理

    问题描述: 在使用ASP.NET的MVC5进行WebAPI开发的时候,在跨域的情况下会报跨域的错, No 'Access-Control-Allow-Origin' header is present ...

  10. PostgreSQL备份和恢复数据表

    备份数据表: pg_dump -U user_name db_name -t table_name -f /tmp/backup_file.suffix 恢复数据表: 方法1: 登录数据库:\i /t ...