zoukankan      html  css  js  c++  java
  • Nhibernate+SQLite 入门实例指南二 类的继承、多态关系

     昨天忘记向源代码下载了,现在补上第一章的代码:https://files.cnblogs.com/9527/QuickStart1.rar

    实例二、类的继承、多态关系

    在我们实际设计过程中,经常碰到类的继承关系,比如一个电子产品商店,同时销售手机和MP3,所以在设计系统的时候我们把手机和MP3的共性如品牌、名称等抽象为一个类,而把它们的特性比如MP3有内存容量,手机有号码等,我们以不同的子类来体现。如下图:

    在实际数据库的时候,最简单的就是每个子类拥有一个独立的表分别对应Mp3player和MobilePhone

    由于MobilePhone和Mp3Player都是继承electronic,所以他们都Id,Name,Brand等属性,了我们分别为两个表编写映射文件:

    MobilePhone.hbm.xml

    <?xml version="1.0" encoding="utf-8" ?> 

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> 

    <class name="QuickStart2.Data.MobilePhone, QuickStart2.Data" table="t_mobilephone" > 

    <id name="Id" column="id" type="Int32"> 

    <generator class="identity" /> 

    </id> 

    <property name="Name" type="String(100)" column="name" /> 

    <property name="Brand" type="String(20)" column="brand" /> 

    <property name="Phonenumber" type="String(13)" column="phonenumber" /> 

    </class> 

    </hibernate-mapping> 

    Mp3Player.hbm.xml 

    <?xml version="1.0" encoding="utf-8" ?> 

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> 

    <class name="QuickStart2.Data.Mp3Player, QuickStart2.Data" table="t_mp3player" > 

    <id name="Id" column="id" type="Int32"> 

    <generator class="identity" /> 

    </id> 

    <property name="Name" type="String(100)" column="name" /> 

    <property name="Brand" type="String(20)" column="brand" /> 

    <property name="Mensize" type="Int32" column="mensize" /> 

    </class> 

    </hibernate-mapping> 


    可以看到这两个映射和普通的映射文件没有什么不同。我们编写了一个段测试代码:

    ISession session=null

    ArrayList list
    =null

    try

    session
    =SessionFactory.OpenSession(); 

    list
    =(ArrayList)session.CreateCriteria(typeof(electronic)).List(); 

    }
     

    catch(Exception e) 

    System.Console.WriteLine(e.Message); 

    System.Console.ReadLine(); 

    }
     

    finally

    session.Close(); 

    }
     

    foreach(electronic el in list) 

    System.Console.WriteLine(
    "名称:º"+el.Name); 

    }
     

    运行结果如下图所示:

    我们看到NHibernate更据electronic自动找到它的两个子类Mp3Player和MobilePhone,生存两铁丝SQL语句分别查询两个表,下面输出的是,查询出来的结果。

    为什么会这样子,在NHibernate中是用多态(polymorphism)来进行描述两个继承于同一父类的子类情况,在映射文件的Class节点中也有一个polymorphism的属性用来设定是隐式还是显式的使用查询多态,为什么我们的映射类中没有出现这个属性的设定呢,polymorphismimplicit是默认的。所以我们如果进行的是隐式的查询就可以不用进行设定。以下是摘自博客园renrenqq 翻译的NHibernate中文文档中对polymorphism的解释:

    Implicit (隐式)的多态是指,如果查询中给出的是任何超类、该类实现的接口或者该类的名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。Explicit (显式)的多态是指,只有在查询中给出的明确是该类的名字时才会返回这个类的实例;同时只有当在这个 <class> 的定义中作为 <subclass> 或者 <joined-subclass> 出现的子类,才会可能返回。 大多数情况下,默认的polymorphism="implicit"都是合适的。 显式的多态在有两个不同的类映射到同一个表的时候很有用。(允许一个轻型的类,只包含部分表字段)。

    通过这样的方式我们虽然也实现了我们想要的结果,但是对经验丰富的设计人员来说,这样的设计是并不合理的,一旦父类分生了变动,数据库里两个表都必须修改,而且从性能角度上来说也并不怎么理想。

    所以,更据经验我们一般会吧两个表相同的字段合并成一个表,另建两个新表,只包含Mp3Player和MobilePhone的特有的属性。经过修改我们的数据库结构如下图如示:

    可以看到主表于子表之间通过外键向连。

    数据库修改以后,我们要重新设计映射文件,让它正确的映射到关系型数据库。

    Electronic.hbm.xml

    <?xml version="1.0" encoding="utf-8" ?> 

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> 

    <class name="QuickStart2.Data.electronic, QuickStart2.Data" table="t_electronic"> 

    <id name="Id" column="id" type="Int32"> 

    <generator class="identity" /> 

    </id> 

    <property name="Name" type="String(100)" column="name" /> 

    <property name="Brand" type="String(20)" column="brand" /> 

    <joined-subclass name="QuickStart2.Data.MobilePhone,QuickStart2.Data" table="t_mobile"> 

    <key column="id" /> 

    <property name="Phonenumber" type="String(13)" column="phonenumber" /> 

    </joined-subclass> 

    <joined-subclass name="QuickStart2.Data.Mp3Player,QuickStart2.Data" table="t_mp3"> 

    <key column="id" /> 

    <property name="Mensize" type="Int32" column="mensize" /> 

    </joined-subclass> 

    </class> 

    </hibernate-mapping> 

    通过映射文件我们可以看到,我们为主类建立了映射,两个子类在<joined-subclass>节点下进行了配置。

    我们现编写一段数据插入代码来看看,NHibernate是怎么进行数据插入的

    public static void SaveMobilephone() 



    ISession session
    =null

    ITransaction t
    =null

    try 



    session
    =SessionFactory.OpenSession(); 

    t
    =session.BeginTransaction(); 

    MobilePhone mp
    =new MobilePhone(); 

    mp.Name
    ="575"

    mp.Brand
    ="Dopod"

    mp.Phonenumber
    ="13151921698"

    Mp3Player mp3
    =new Mp3Player(); 

    mp3.Name
    ="SB200"

    mp3.Brand
    ="小霸王"

    mp3.Mensize
    =513

    session.Save(mp3); 

    session.Save(mp); 

    session.Flush(); 

    t.Commit(); 

    }
     

    catch(HibernateException e) 



    System.Console.Write(e.Message.ToString()); 

    if(t!=null



    try 



    t.Rollback(); 

    }
     

    catch(HibernateException e1) 



    System.Console.Write(e1.Message.ToString()); 

    }
     

    }
     

    }
     

    finally 



    session.Close(); 

    }
     

    System.Console.ReadLine(); 

    }
     

    编译运行如上代码,在返回中我们看到如下结果

    根据图片,我们可以看到,和前一次不同,NHibernate分四次,分别对主表和子表进行插入。

    在运行我们在上一节中的查询代码,其结果是

    我们可以看到,NHibernate用了一条组合查询,一次性就把三个表所有数据查询了出来。

    从上面的例子我们可以看到,这样的设计,虽然从设计的逻辑上来说更加清晰明了,符合我们的设计习惯,但是多表操作带来的性能的消耗来是相当的可观,因此,如果我们的系统对性能上有相当的要求,我们就要考虑第三种方式。

    我们把数据设计成不仅包含用父类的共同属性,也同是用不同的字段来表示两种产品的不同特性,这样如何来区别两个类呢,我们在数据库中加入一个”category”的字段来区别两种产品。

    代码方面我们需要修改的也只有数据库的映射文件,把新映射文件修改成如下:

    <?xml version="1.0" encoding="utf-8" ?> 

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> 

    <class name="QuickStart2.Data.electronic, QuickStart2.Data" table="t_elec"> 

    <id name="Id" column="id" type="Int32"> 

    <generator class="identity" /> 

    </id> 

    <discriminator column="category" type="String(10)" /> 

    <property name="Name" type="String(100)" column="name" /> 

    <property name="Brand" type="String(20)" column="brand" /> 

    <subclass name="QuickStart2.Data.MobilePhone,QuickStart2.Data" discriminator-value="1" > 

    <property name="Phonenumber" type="String(13)" column="phonenumber" /> 

    </subclass> 

    <subclass name="QuickStart2.Data.Mp3Player,QuickStart2.Data" discriminator-value="2" > 

    <property name="Mensize" type="Int32" column="mensize" /> 

    </subclass> 

    </class> 

    </hibernate-mapping> 

    于前一节中的映射文件不一样的是,我们在映射文件中加入了一个识别器(discriminator),用来指定数据库中哪个字段是用来做为标识的。

    在定义的子类的时候,也不能用joined-subclass 而要改成subclass joined-subclass不能支持discriminator-value属性,discriminator-value就是用来区分独立的子类当我们完成数据库的插入操作后(具体代码可以用上一节所提供的代码,由于代码完全相同,所以不再次提供了)我们可以看到,NHibernate只用了两次插入动作就完成了对数据的插入。

    我们再运行查询的代码也可以用一条简单的SQL语句来完成操作,大家也可以试着用

    list=(ArrayList)session.CreateQuery("from Mp3player").List();

    list=(ArrayList)session.CreateQuery("from MobilePhone").List();

    进行查询,在NHibernate生的结果如下图:

    可以看到,NHibernate在读取数据的时候会自动更据标识读取Mp3Player或MobilePhone的内容。

    但是这种方法也有它的硬伤,如果子类的特性太多,哪数据库的可读性就大打折扣了,甚至可以让人抓狂,对于系统的后期维护升级非常的不利。

    因此、三种方法各有各的优点也各有缺点,我们要在设计的过程中更据实际情况进于权衡,然后才确定采用何种方式。
    第二章代码下载:https://files.cnblogs.com/9527/QuickStart2.rar

  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/9527/p/513505.html
Copyright © 2011-2022 走看看