ORM中的继承关系映射全解——单表继承体系、一实体一具体表、一实体一扩展表

ORM中的继承关系映射全解——单表继承体系、一实体一具体表、一实体一扩展表、接口映射

本文涉及的内容包括:

1.单表继承体系

2.一实体一具体表

3.一实体一扩展表

4.接口实现映射vs基类继承映射

1.单表继承体系

所谓单表继承体系就是用一张数据库表存储整个继承体系中的所有实体的数据。单表继承体系适合那种继承体系中实体数目相对较少,总记录数相对较少,子类对父类的属性扩展也相对较少的情形。

单表继承体系优点是读/写继承体系中的每个实体的数据,都只需操作一张表,性能较好,并且,新增继承类,或扩展实体属性都只需要增减一张表的字段就可以了,易于维护;主要缺点是,因为所有的实体共享一张表,表中会有比较多的NULL字段值的数据,浪费了一些存储空间,同时,如果记录数过多,表就会更庞大,也会影响表的读写性能。

简单单表继承体系

让我们先看一个假象的例子:

[Table("AllInOneTable")]
public interface Parent : IEntity
{
 [PrimaryKey]
 int ID { get; }
 string Name { get; set; }
}
[Table("AllInOneTable")]
public interface AnotherParent : IEntity
{
 [PrimaryKey]
 int ID { get; }
 int Age { get; set; }
}
[Table("AllInOneTable")]
public interface Child : Parent, AnotherParent
{
 [PrimaryKey]
 new int ID { get; set; }
 DateTime Birthday { get; set; }
}

我们可以看到,在上例中,我们定义了两个基实体Parent和AnotherParent,Child实体同时从两个基类继承。注意,代码中加粗的行,如果多个不同的基接口包含相同名称的属性,代码会编译失败,此时,需要像这样使用new关键字来避免编译失败。

这里,我们采用的是单表继承体系方式,注意每个实体都映射到AllInOneTable这个表,只不过对每个实体来说,只使用了AllInOneTable表的部分字段。

但是,以这样的简单方式定义单表继承时,因为从表中读数据时无法知道一行数据真正对应的是哪一个子类,所以,实际情况下,一般我们都要附加一些查询条件和字段默认值。

带附加条件的单表继承体系

采用单表继承体系方案时,继承体系中的不同子类不仅仅扩展父类的属性,肯定还会附带一些字段查询条件和默认值。这里会用到NBear.Common.TableAttribute的AdditionalWhere和AdditionalInsert属性,关于这两个属性的详细用法请参考表映射。

请看下面的代码:

public interface Message : IEntity
{
 [PrimaryKey]
 int ID { get; }
 string Title { get; set; }
 string Content { get; set; }
 DateTime UpdateTime { get; set; }
}
[Table("Message", AdditionalInsert = "[MessageType] = 1", AdditionalWhere = "[MessageType] = 1")]
public interface CommonMessage : Message
{
 int UserID { get; set; }
}
[Table("Message", AdditionalInsert = "[MessageType] = 2", AdditionalWhere = "[MessageType] = 2")]
public interface SpecialMessage : Message
{
 int GroupID { get; set; }
}

这里我们实际要持久化的是两个实体CommonMessage和SpecialMessage,他们有一个共同的抽象父类Message,父类作为一个抽象类不会被直接使用。我们将整个继承体系存于Message数据表。包含CommonMessage和SpecialMessage的所有属性。但是,就像我们在上面的假象示例中所说的,如果直接查询Message表,返回CommonMessage对应的字段数据,那么连SpecialMessage插入的那些数据也会被返回,反之亦然,这显然是不符合要求的。

因此,我们需要定义附加的查询条件和插入默认值,即为Message表增加一个MessageType字段,该字段值为1的数据代表CommonMessage,值为2代表该行数据是SpecialMessage,如上面的代码中定义AdditionalWhere和AdditionalInsert后,查询CommonMessage或SpecialMessae时,就只会返回真正对应到他们的MessageType值的记录了;当插入数据时,为CommonMessage和SpecialMessage,框架也会自动为其设置必要的MessageType默认值。

时间: 2016-05-15

ORM中的继承关系映射全解——单表继承体系、一实体一具体表、一实体一扩展表的相关文章

Python中类型关系和继承关系实例详解

  本文详细介绍了Python中类型关系和继承关系.分享给大家供大家参考.具体分析如下: 如果一个对象A持有另一个对象B的ID,那么检索到A之后就可以检索到B,我们就说存在一个A到B的导航.这种导航关系使得Python中所有对象之间形成了一个复杂的网络结构. Python程序的运行包括: 1. 修改这个网络结构; 2. 执行有副作用的代码对象(code object或者说bytecode,见Python Language Reference 3.2) (副作用是指影响Python虚拟机之外的设备

Word2007中剪贴画的插入全解

  在word2007中,插入图片的时候,常常会看到"剪贴画"的字眼,剪贴画是提供文档装饰素材的两一个来源,与图片不同,而在word2007中想要插入剪贴画,可以从哪些途径获得呢?下面就来详细了解下. word2007 中" 剪贴画 "是提供文档装饰素材的另一个来源,当可视化有帮助时它常用于简讯和床单.作为"office共享功能"集的一部分,根据安装的 Office 程序和安装内容的多少,"剪贴画"有数百甚至数千个免费的小图形

精通Hibernate之映射继承关系八

由于关系数据模型不允许一个表的外键同时参照两个表的主键,因此无法对TABLE_D表的A_ID字段定义外键参照约束,而应该通过其他方式,如触发器,来保证A_ID字段的参照完整性.由于TABLE_D表的A_ID字段既可能参照TABLE_B表的ID主键,也可能参照TABLE_C表的ID主键,要求TABLE_B表和TALBE_C表的ID主键具有相同的SQL类型. 在ClassD.hbm.xml文件中,用元素来映射ClassD的a属性: <any name="a" meta-type=&q

精通Hibernate之映射继承关系一

在域模型中,类与类之间除了关联关系和聚集关系,还可以存在继承关系,在图14-1所示的域模型中,Company类和Employee类之间为一对多的双向关联关系(假定不允许雇员同时在多个公司兼职),Employee类为抽象类,因此它不能被实例化,它有两个具体的子类:HourlyEmployee类和SalariedEmployee类.由于Java只允许一个类最多有一个直接的父类,因此Employee类.HourlyEmployee类和SalariedEmployee类构成了一棵继承关系树. }else

在Entity Framework中使用存储过程(二):具有继承关系实体的存储过程如何定义?

在<实现存储过程的自动映射>中,我通过基于T4的代码生成实现了CUD存储过程的自动映射.由于映射的都是基于数据表结构的标准的存储过程,所以它们适合概念模型和存储模型结构相同的场景.如果两种模型存在差异,在进行数据更新操作的时候就会出错.本篇文章主要介绍当概念模型中具有继承关系的两个实体映射到数据库关联的两个表,如何使用存储过程. 目录 一.创建具有继承关系的实体 二.基于继承关系实体的查询与更新 三.映射标准的CUD存储过程 四.修正存储过程 一.创建具有继承关系的实体 假设数据库中有如下两个

浅析Hibernate继承关系树的三种映射方式

在向大家详细介绍Hibernate继承关系树的三种映射方式之前,首先让大家了解下Employee类为抽象类,然后全面介绍. 在域模型中,类与类之间除了关联关系和聚集关系,还可以存在继承关系,Company类和Employee类之间为一对多的双向关联关系(假定不允许雇员同时在多个公司兼职),Employee类为抽象类,因此它不能被实例化,它有两个具体的子类:HourlyEmployee类和 SalariedEmployee类.由于Java只允许一个类最多有一个直接的父类,因此Employee类.H

【HIBERNATE框架开发之七】HIBERNATE使用ANNOTATION中各种关系映射的CRUD(增删改查)&amp;&amp;集合映射&amp;&amp;继承映射

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/hibernate/822.html       首先对于Annotation中CRUD的C(Create)操作:-------- 假设 :   User (MonyToOne)       Group OK,那么有如下 Junit Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Conf

自己动手写ASP.NET ORM框架(三):关系映射配置—Table属性

在上一篇随笔中已经完成了ADO.NET操作数据库的封装,并已经支持多数据库,只需要在 配置文件中指定数据库类型即可,本节主要完成对象与数据库表的关系映射配置. 下面看表名的映射配置代码块1-1: [Table(Name="Student")] public class StudentEntity { //...........省略 } 在类上面用[Table(name = "Student")]属性来配置,表示该实体类StudentEntity与数 据库中的Stud

精通Hibernate之映射继承关系七

Company与Employee类之间为一对多多态关联关系,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么就能映射Company类的employees集合.本节介绍如何映射多对一多态关联.如图14-11所示,ClassD与ClassA为多对一多态关联关系. 假定与ClassD对应的表为TABLE_D,与ClassA对应的表为TABLE_A,在TABLE_D中定义了外键A_ID,它参照TABLE_A表的主键. ClassD对象的a属性既可以引用ClassB对象,也可以引用ClassC对