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 ...
随机推荐
- 在Struts2 Action中快速简便的访问Request、Session等变量
前言——正常情况下如何在Action中获取到这些变量 全部方法(共四种)可以参考:http://blog.csdn.net/itmyhome1990/article/details/7019476 这 ...
- 【linux】如何解决VMWare上linux虚拟机连不上外网的问题?
>>>故障现象:虚拟机连接不到外网? >>>故障背景: Centos7.4发行版本: 虚拟机和VM软件都是nat模式: 注意这里默认的VMWare的DHCP服务时开 ...
- 初识MVC框架
MVC框架 是一个框架模式,它使应用程序的输入.处理和输出分开.它可以使业务逻辑.数据.界面显示分离,使得耦合度大大降低,在这一方面与"三层"思想类似. M--Model ...
- EXTJS4.0 显示图片 动态图片
在网上找了好久没有好的解决方法 都是用 'box' 什么的组件 改写的 autoEl 好麻烦,修改 好的属性都不能用.弄了好久没弄成 最后: 用panel 显示 html 文本 追加 ‘'<i ...
- log4net配置,正在用
<?xml version="1.0" encoding="utf-8" ?> <log4net> <appender name= ...
- 行为型设计模式之命令模式(Command)
结构 意图 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 适用性 抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(c a ...
- artDialog组件与iframe
背景 组件官网. 未用过的朋友可以先了解下. 当Content参数传递html元素时,官方的解释是: 备注:1.元素不是复制而是完整移动到对话框中,所以原有的事件与属性都将会保留 2.如果隐藏元素被传 ...
- BZOJ1588 [HNOI2002]营业额统计 splay模板
1588: [HNOI2002]营业额统计 Time Limit: 5 Sec Memory Limit: 162 MB Submit: 16189 Solved: 6482 [Submit][S ...
- MVC5 WebAPI 跨域处理
问题描述: 在使用ASP.NET的MVC5进行WebAPI开发的时候,在跨域的情况下会报跨域的错, No 'Access-Control-Allow-Origin' header is present ...
- PostgreSQL备份和恢复数据表
备份数据表: pg_dump -U user_name db_name -t table_name -f /tmp/backup_file.suffix 恢复数据表: 方法1: 登录数据库:\i /t ...