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 ...
随机推荐
- Eclipse下使用SVN插件从服务器获取工程
1.打开Eclipse 4.4,在Eclipse里打开SVN资源库窗口:点击菜单window-->show view-->other:然后再弹出窗口展开SVN节点,选择SVN资源库 2 ...
- springmvc项目搭建三-添加前端框架
这几年前端框架发展可以说非常迅猛了...实际项目中也用到了几个,easyui相对来讲,算是我第一个接触的前端框架了,用的时候感觉很方便,省了很多代码量,一个好的前端框架可以为你省去很多精力在前端布局上 ...
- POJ 2243 [SDOI2011]染色 | 树链剖分+线段树
原题链接 肯定是树链剖分的题啦 树剖怎么做可以看我上一篇博客 如果我们已经剖完了: 然后考虑怎么维护重链和查询 用线段树维护的时候当前区间的区间颜色个数应该等于左儿子+右儿子,但是当左儿子的右端点和右 ...
- 2017 多校4 Security Check
2017 多校4 Security Check 题意: 有\(A_i\)和\(B_i\)两个长度为\(n\)的队列过安检,当\(|A_i-B_j|>K\)的时候, \(A_i和B_j\)是可以同 ...
- 使AD域控服务器Administrator的密码永不过期方法。
在安装完AD域后,管理员密码会42天就要更新一次,这样对测试比较不方便, 如果要让域控管理员账号密码永远不过期,就照着下面的方法执行: open a Command Prompt as the adm ...
- ACM-The Coco-Cola Store
题目: Once upon a time, there is a special coco-cola store. If you return three empty bottles to the s ...
- 寻宝游戏(bzoj 3991)
Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...
- codevs 1269 匈牙利游戏——次短路(spfa)
欢迎来到匈牙利游戏!布达佩斯(匈牙利首都)的街道形成了一个弯曲的单向网络. 你被强制要求参加一个赛跑作为一个TV秀的一部分节目,比赛中你需要穿越这些街道,从s开始,到t结束. 很自然的,你想要尽快的完 ...
- 在Framework2.0环境下运行3.5的代码
因为许多的服务器特别是廉价的服务器上使用的是Framework的v2.0.50727.再加上自己开发的算是产品,所以就需要降低一些客户的前期成本,而自己同时也喜欢简单的代码.后来查了下,得知其实Fra ...
- mysql [MariaDB] 开启外联
1.查看mysql服务端口是否为外部端口,如果监听的是本地端口修改mariadb配置文件 root@kali:~# whereis mysql mysql: /usr/bin/mysql /etc/m ...