zoukankan      html  css  js  c++  java
  • 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 frogmodel0_.AnimalId=@p0 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 frogmodel0_.Id=@p0',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 frogmodel0_.AnimalId=@p0 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语句。这还说什么,功能都不全。

  • 相关阅读:
    HDU 1850 Being a Good Boy in Spring Festival
    UESTC 1080 空心矩阵
    HDU 2491 Priest John's Busiest Day
    UVALive 6181
    ZOJ 2674 Strange Limit
    UVA 12532 Interval Product
    UESTC 1237 质因子分解
    UESTC 1014 Shot
    xe5 android listbox的 TMetropolisUIListBoxItem
    xe5 android tts(Text To Speech)
  • 原文地址:https://www.cnblogs.com/kissdodog/p/3333944.html
Copyright © 2011-2022 走看看