NHibernate 继承映射(第十六篇)

在NHibernate的映射中,关于继承的映射策略有3种方式

  • 单表继承
  • 类表继承
  • 具体表继承

  另外还有一种比较特别的多态映射

  • 隐式多态

  下面分别来阐述NHibernate继承映射的各种策略要点。

一、单表继承

  单表继承的方式是,所有的字段都放在一个表中,用一个字段来区分子类。使用配置节点<subclass>配置子类。

  看DEMO,首先新建一张Animal表如下:

  

  映射文件:Animal.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Model.AnimalModel,Model" table="Animal" discriminator-value="动物">
    <id name="AnimalId" column="AnimalId" type="Int32">
      <generator  class="native"/>
    </id>
    <discriminator column="AnimalType" type="String" />  <!-- 指定辨别字段列名,用于SQL语句筛选 -->
    <property name="Name" column="Name" type="String"/>
    <!--subclass放在这里也可以-->
    <subclass extends="Model.AnimalModel, Model" name="Model.FrogModel, Model" discriminator-value="蛙"> //discriminator-value用来标记表中哪些行是青蛙
      <property name="Foot" column="Foot" type="String"/>
    </subclass>
  </class>
</hibernate-mapping>

  映射文件:Fish.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
    <subclass extends="Model.AnimalModel, Model" name="Model.FishModel, Model" discriminator-value="鱼">
      <property name="Tail" column="Tail" type="String"/>
    </subclass>
</hibernate-mapping>

  Model类:

namespace Model
{
    public class AnimalModel
    {
        public virtual int AnimalId { get; set; }
        public virtual string Name { get; set; }
    }
    public class FishModel : AnimalModel
    {
        public virtual string Tail { get; set; }
    }
    public class FrogModel : AnimalModel
    {
        public virtual string Foot { get; set; }
    }
}

  执行操作:

        static void Main(string[] args)
        {
            ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
            using (ISession session = sessionFactory.OpenSession())
            {
                FishModel Fish = session.Get<FishModel>(1);
                Console.WriteLine(Fish.AnimalId + " : " + Fish.Name + " : " + Fish.Tail);

                FrogModel Frog = session.Get<FrogModel>(2);
                Console.WriteLine(Frog.AnimalId + " : " + Frog.Name + " : " + Frog.Foot);
            }
            Console.ReadKey();
        }

  输出结果如下:

  

  我们看看SQL Server Profiler监控到执行的存储过程:

exec sp_executesql N‘SELECT frogmodel0_.AnimalId as AnimalId0_0_, frogmodel0_.Name as Name0_0_, frogmodel0_.Foot as Foot0_0_ FROM Animal frogmodel0_ WHERE [email protected] and frogmodel0_.AnimalType=‘‘蛙‘‘,N‘@p0 int‘,@p0=2

  我们看到NHibernate,会利用我们设置的discriminator-value的值去过滤数据。使用单表继承,特别需要注意的就是, 由子类定义的字段,不能有非空约束(not-null)。为什么?因为,如上面的Foot与Tail。青蛙则尾巴字段为空,鱼则肯定腿字段为空。

二、类表映射

  类表映射,故名思议就是一个子类一个表,其子类表通过外键关联到主表。然后一个子类对应一张表。配置节点为:<joined-subclass>

  首先我们将上面的表结构改为:

  

  映射文件的改动如下,Animal.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Model.AnimalModel,Model" table="Animal"> <!--去掉discriminator-value,类表映射这个属性没用了-->
    <id name="AnimalId" column="AnimalId" type="Int32">
      <generator  class="native"/>
    </id>
    <discriminator column="AnimalType" type="String" />
    <property name="Name" column="Name" type="String"/>
    <joined-subclass extends="Model.AnimalModel, Model" name="Model.FrogModel, Model" table="Frog"> <!--增加表名-->
      <key column="Id"/>  <!--添加主键Id-->
      <property name="Foot" column="Foot" type="String"/>
    </joined-subclass>    <!--joined-subclass-->
  </class>
</hibernate-mapping>

  Fish.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  <joined-subclass extends="Model.AnimalModel, Model" name="Model.FishModel, Model" table="Fish">
      <key column="Id"/>
      <property name="Tail" column="Tail" type="String"/>
    </joined-subclass>
</hibernate-mapping>

  Program.cs不用改,输出结果也和上面一样,需要改变的仅仅是数据库表与映射文件。

  我们来看看SQL Server Profiler监控到执行了什么语句:

exec sp_executesql N‘SELECT frogmodel0_.Id as AnimalId0_0_, frogmodel0_1_.Name as Name0_0_, frogmodel0_.Foot as Foot1_0_ FROM Frog frogmodel0_ inner join Animal frogmodel0_1_ on frogmodel0_.Id=frogmodel0_1_.AnimalId WHERE [email protected]‘,N‘@p0 int‘,@p0=2

  一个简单的inner join实现的。

  可以看到,使用这种方式的表比较多,关系模型实际是一对一关联。

类表映射使用Discriminator

  类表映射还可以加上个辨别字段,只是它除了用外键关联之外,还有个辨别字段。配置节点为<subclass><join>。

  现在,我们为上面的表结构再添加会一个辨别字段:

  

  映射文件Animal.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Model.AnimalModel,Model" table="Animal" discriminator-value="动物"> <!--增加回辨别字段-->
    <id name="AnimalId" column="AnimalId" type="Int32">
      <generator  class="native"/>
    </id>
    <discriminator column="Type" type="String" /> <!--指定辨别字段列名,会用在SQL语句-->
    <property name="Name" column="Name" type="String"/>
    <subclass extends="Model.AnimalModel, Model" name="Model.FrogModel, Model"  discriminator-value="蛙"> <!--增加回辨别字段-->
      <join table="Frog"> <!--增加join节点-->
        <key column="Id"/>
        <!--添加主键Id-->
        <property name="Foot" column="Foot" type="String"/>
      </join>
    </subclass>    <!--joined-subclass-->
  </class>
</hibernate-mapping>

  Fish.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  <subclass extends="Model.AnimalModel, Model" name="Model.FishModel, Model" discriminator-value="鱼">
    <join table="Fish">
      <!--增加join节点-->
      <key column="Id"/>
      <property name="Tail" column="Tail" type="String"/>
    </join>
    </subclass>
</hibernate-mapping>

  Program.cs不变,输出结果不变。我们来看看生成的SQL语句:

exec sp_executesql N‘SELECT frogmodel0_.AnimalId as AnimalId0_0_, frogmodel0_.Name as Name0_0_, frogmodel0_1_.Foot as Foot1_0_ FROM Animal frogmodel0_ inner join Frog frogmodel0_1_ on frogmodel0_.AnimalId=frogmodel0_1_.Id WHERE [email protected] and frogmodel0_.Type=‘‘蛙‘‘,N‘@p0 int‘,@p0=2

  另外,在映射文件里,可以混合使用单表映射与类表映射,例如

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Model.AnimalModel,Model" table="Animal" discriminator-value="动物"> <!--增加回辨别字段-->
    <id name="AnimalId" column="AnimalId" type="Int32">
      <generator  class="native"/>
    </id>
    <discriminator column="Type" type="String" /> <!--指定辨别字段列名,会用在SQL语句-->
    <property name="Name" column="Name" type="String"/>
    <subclass extends="Model.AnimalModel, Model" name="Model.FishModel, Model" discriminator-value="鱼">  <!--单表映射-->
      <join table="Fish">
        <key column="Id"/>
        <property name="Tail" column="Tail" type="String"/>
      </join>
    </subclass>
    <joined-subclass extends="Model.AnimalModel, Model" name="Model.FrogModel, Model" table="Frog">  <!--类表映射-->
      <key column="Id"/>
      <property name="Foot" column="Foot" type="String"/>
    </joined-subclass>
  </class>
</hibernate-mapping>

三、具体表映射

  看了一下具体表映射的说明,决定不写了。这种方法实在太烂。不光表多,重复字段也多,我操。

  子类表中,每张表为对应类的所有属性(包括从超类继承的属性)定义相应字段。

  重复列太多,再加上每个类都一张表,第一范式都达不到吧。果断放弃。

四、隐式多态

  有一个缺点,无法生成有union的SQL语句。这还说什么,功能都不全。

时间: 2024-10-29 19:08:07

NHibernate 继承映射(第十六篇)的相关文章

Python之路【第十六篇】:Django【基础篇】

Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: python manage.py runserver

跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint

目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinpoint架构简介 5. Pinpoint数据结构简介 6. Pinpoint版本依赖 7. Spring Cloud与Pinpoint实战 8. 小结 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint Springboot: 2.1.7.RELEASE Sp

秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035 转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902 欢迎关注微博:http://weibo.com/MoreWindows 在<秒杀多线程系列>的前十五篇中介绍多线程的相关概念,多线程同步互斥问题<秒杀多

第十六篇 人类世界

第十六篇  人类世界 人类世界是一个快速发展的世界.在这个宇宙中人类物种出现的时间并不算很长,随着大宇宙的发展,在宇宙经历了多次调整①之后,人类物种是在宇宙发展需要的情况下才被创造的,可以说我们人类物种算是出现在一个非常好的时间点上. 也就是说,人类物种在被创造之前已经有很多高智慧物种为人类打下了良好的基础,这些基础能够让人类这个物种在宇宙中得到快速的发展.如果没有这样的基础,人类世界也不会发展得如此庞大. 人类带着创造者的期待与信任出现在这个宇宙中,开始了人类生命的历程.由于人类这个物种肩负着

NHibernate 集合映射深入 (第五篇) &lt;set&gt;,&lt;list&gt;,&lt;map&gt;,&lt;bag&gt;

NHibernate 集合映射深入 (第五篇) <set>,<list>,<map>,<bag> 一.集合外键 在NHibernate中,典型的用于映射集合类的元素有<set>,<list>,<map>,<bag>,<array>,<primitive-array>. 我们回到上一篇,集合映射基础当中的一对多查询.对于集合类型: public virtual ISet<Person

解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)

解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译) http://improve.dk/orcamdf-rawdatabase-a-swiss-army-knife-for-mdf-files/ 当我最初开始开发OrcaMDF的时候我只有一个目标,比市面上大部分的书要获取MDF文件内部的更深层次的知识 随着时间的推移,OrcaMDF确实做到了.在我当初没有计划的时候,OrcaMDF 已经可以解析系统表,元数据,甚至DMVs.我还做了一个简单U

Python开发【第十六篇】:AJAX全套

Python开发[第十六篇]:AJAX全套 概述 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要重新加载全局数据 2.AJAX AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案. 异步的JavaScript:使用 [JavaScript语言] 以

第二十六篇:USB3.0高带宽ISO(48KBytes/125us)实战

USB3.1技术已经推出, 10Gbps的速率足以满足数据, HD视频传输的要求. 要步入USB3.1的研发, 还得将USB3.0的基础打扎实. 微软提供的SUPER MUTT只包含一个接口0, 其下有两个ALT, ALT 1与ALT 2, 分别包含了两对ISO IN/OUT端点, 不过, 只有ALT 2下的ISO OUT EP的bMaxBurst为1, 而其它三个ISO EP的bMaxBurst均为0, 而所有的ISO EP的Mult均为0. 即只有一个ISO EP支持2KBytes/125u

Egret入门学习日记 --- 第三十六篇(书中 10.7 ~ 10.8 节 内容)

第三十六篇(书中 10.7 ~ 10.8 节 内容) 开始 书中 10.7 节内容. 书中 10.7 节内容结束. 书中重点: 1.导出素材. 2.配置粒子库. 3.播放动画. 开始操作: 1.导出素材. 我设置好了雪花的效果. 接着是导出. 这是导出后的资源文件. 导入Egret的预加载资源组中. 2.配置粒子库. 下载好官方的粒子库. https://github.com/egret-labs/egret-game-library 拷贝粒子库到项目外,记住 项目文件夹外! 配置好 egret