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语句。这还说什么,功能都不全。

  • 相关阅读:
    Git ---游离状态下的commit 分支切换与找回,commit之后无法找到历史记录
    mybatis异常invalid comparison: java.util.Date and java.lang.String
    Spring的注解@Qualifier
    Spring @Bean注解的使用
    Java的IO系统
    linkin大话面向对象--GC和jar包
    linkin大话面向对象--闭包和回调
    linkin大话面向对象--内部类
    linkin大话面向对象--枚举
    linkin大话面向对象--接口
  • 原文地址:https://www.cnblogs.com/kissdodog/p/3333944.html
Copyright © 2011-2022 走看看