NHibernate官方文档——第八章 继承映射(Inheritance Mapping)
本文翻译自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 |
NHibernate官方文档——第八章 继承映射(Inheritance Mapping)的更多相关文章
- NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)
映射声明 对象/关系映射在XML文件中配置.mapping文件这样设计是为了使它可读性强并且可修改.mapping语言是以对象为中心,意味着mapping是围绕着持久化类声明来建立的,而不是围绕数据表 ...
- NHibernate官方文档中文版--ISessionFactory的配置(ISessionFactory Configuration)
由于NHibernate是被设计应用在许多不同环境中的,因此它存在很多配置参数.幸运的是,这些参数大多都有合理的默认值,而且NHibernate发布的时候伴随着一个App.config 例子(可在sr ...
- NHibernate官方文档中文版——批量插入(Batch inserts)
A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this: 一 ...
- NHibernate官方文档中文版--只读实体类型(Read-only entities)
重点 NHIbernate处理只读对象的方式可能和你在别处看到的不同.不正确的使用方式可能造成不可预料的结果. 当一个实体是只读的时候: NHIbernate不会对实体的简单属性和单向关联数据检查数据 ...
- NHibernate官方文档中文版——事务和并发(Transactions And Concurrency)
NHibernate本身并不是一个数据库.它是一个轻量级的对象-关系映射工具.因此,它的事务管理代理给对应的数据库连接.如果这个连接代理了一个分布式的事务,ISession管理的操作就会自动成为整个分 ...
- NHibernate官方文档中文版-框架架构(Architecture)
总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ...
- NHibernate官方文档中文版——持久化类(Persistent Classes)
持久化类是一个应用程序中的类,主要用来实现业务逻辑(例如,在电商应用中的客户和订单类).持久化类,就像它的名字一样,生命周期短暂并且用来持久化的据库对象实例. 如果这些类的构造能够依照一些简单的原则, ...
- NHibernate官方文档中文版--拦截器和事件(Interceptors and events)
对于应用程序来说,能够对NHibernate内部发生的事件做出响应式很有用的.这能够有助于实现一些类的功能或者扩展NHibernate的功能. 拦截器 IInterceptor接口提供了应用程序ses ...
- OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)
OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...
随机推荐
- [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结
来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...
- kibana的查询语法
kibana的查询语法是 字段Fields:关键词
- P1194 买礼物
题目描述 又到了一年一度的明明生日了,明明想要买B样东西,巧的是,这B样东西价格都是A元. 但是,商店老板说最近有促销活动,也就是: 如果你买了第I样东西,再买第J样,那么就可以只花K[I,J]元,更 ...
- [AGC008E] Next or Nextnext [环套树森林+结论讨论]
题面 传送门 思路 p到a 首先,本题中如果对于所有的$i$,连边$<i,p_i>$,那么可以得到一批环 那么这个题另外一点就是,可以变成连边$<i,p_{p_i}>$ 我们分 ...
- ZOJ 1081 Points Within | 判断点在多边形内
题目: 给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部 题解: 网上有两种方法,这里写一种:射线法 大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方 ...
- BZOJ5301 [Cqoi2018]异或序列 【莫队】
题目链接 BZOJ5301 题解 莫队水题 BZOJ400AC纪念 #include<algorithm> #include<iostream> #include<cst ...
- java算法(二) 快速排序
快速排序是一种交换排序. 快速排序由C. A. R. Hoare在1962年提出. 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数. 然后再 ...
- mysql5.6免安装配置(菜鸟版)
mysql5.6免安装配置 MySQL5.6.13安装步骤(Windows7 32位) 1. 下载MySQL Community Server 5.6.13 2. 解压MySQL压缩包 将以下载的My ...
- 编写Shell脚本的最佳实践,规范二
需要养成的习惯如下: 代码有注释 #!/bin/bash # Written by steven # Name: mysqldump.sh # Version: v1.0 # Parameters : ...
- 校内训练0602 习题exercise
[题目大意] f(i)=((Af(i-1)+B)/(Cf(i-1)+D)) mod P. 给出f(0), A, B, C, D, P, n,求f(n). 多组数据T<=1e4 n<=1e1 ...