zoukankan      html  css  js  c++  java
  • NHibernate之(2):第一个NHibernate程序

    本节内容

    • 开始使用NHibernate
    • 1.获取NHibernate
    • 2.建立数据库表
    • 3.创建C#类库项目
    • 4.设计Domain
      • 4-1.设计持久化类
      • 4-2.编写映射文件
    • 5.数据访问层
      • 5-1.辅助类
      • 5-2.编写操作
    • 6.数据访问层的测试
      • 6-1.配置NHibernate
      • 6-2.测试
    • 结语

    开始使用NHibernate

    以一个实际场景电子交易程序来模拟,客户/订单/产品的经典组合。由于是第一次使用NHibernate,所以我们的目的是映射一张表并完成使用NHibernate来读取数据,下面的一幅图片给了我们第一印象。我们按照基本开发软件思想的流程一步一步完成。

    我使用的开发环境:Microsoft Visual Studio 2019、SQL Server 2014 Express、NHibernate 5.3.0.0。

    ORM

    1.获取NHibernate

    如果你第一次使用NHibernate,先到这里下载NHibernate最新版本(包括源码、发布版本、参考文档、API文档,可选择下载)。关于NHibernate-5.3.0.0的更多信息请点击这里

    注意

    NHibernate 3.2或以上的版本就没有
    NHibernate.ByteCode.Castle.dll,
    NHibernate.ByteCode.LinFu.dll, NHibernate.ByteCode.Spring.dll 这三个DLL了,

    hibernate.cfg.xml 配置文件中的 proxyfactory.factory_class要修改如下: 
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property> 
    不然会报错。

    proxyfactory.factory_class 节点不是必选配置。

    2.建立数据库表

    由于第一次使用,还是按照我们传统的从数据库表配置吧。

    打开SQL Server Management Studio Express,新建一个新的数据库NHibernateOper,创建四个表:分别为客户表、订单表、订单产品表、产品表。

    3.创建C#类库项目

    由于是我们第一个程序,所以我没有按照Domain Driver Design方法去设计这个程序,按照大家的常规思想来实现的,以后有机会再介绍Domain Driver Design设计。

    注意为什么创建C#类库项目呢?在现在软件设计中,大多数都是采用多层架构来设计,比较经典的三层架构(页面表示层,业务逻辑层,数据访问层)通常而言业务逻辑层和数据访问层都是使用类库设计,页面表示层用Web应用程序设计,它引用业务逻辑层和数据访问层类库DLL程序集。

    使用VS2008创建C#类库的项目,命名为NHibernateSample。打开项目文件夹,在其项目文件目录上新建SharedLibs文件夹,把下载NHibernate相关程序集文件拷贝到SharedLibs文件夹下。如下图,这里我选择Castle框架动态代理:

    创建项目,结构如下:

     

    • Domain(领域模型):处理业务逻辑(未实现)
    • DomainModel:存放数据库实体模型
    • Repository(Data Access Layer数据访问层):定义对象的CRUD操作
    • Test(数据访问层测试):对数据访问层的测试,这里我使用Nunit单元测试框架
    • Web:Web页面(这篇文章中暂未实现)
    • Utility:一些通用方法,比如NHibernateHelper之类
    项目引用
    • Test:引用Repository,DomainModel
    • Repository:引用DomainModel,NHibernate.dll(5.3.0.0),Utility

    4.设计Domain

    4-1.编写持久化类

    按简单传统.NET对象(POCOs,Plain Old CLR Objects(Plain Ordinary CLR Objects))模型编程时需要持久化类。在NHibernate中,POCO通过.NET的属性机制存取数据,就可以把它映射成为数据库表。

    现在为Customer编写持久化类来映射成为数据库表。新建一个Customer.cs类文件:

    namespace NHibernateOper.DomainModel
    {
        public class Customer
        {
            public virtual int CustomerId { get; set; }
            public virtual string Firstname { get; set; }
            public virtual string Lastname { get; set; }
        }
    }
    规则
    • NHibernate使用属性的getter和setter来实现持久化。
    • 属性可设置为public、internal、protected、protected internal或private
    注意NHibernate默认使用代理功能,要求持久化类不是sealed的,而且其公共方法、属性和事件声明为virtual。在这里,类中的字段要设置为virtual,否则出现“failed: NHibernate.InvalidProxyTypeException : The following types may not be used as proxies: NHibernateSample.Domain.Entities.Customer: method get_Id should be virtual,method set_Id should be virtual”异常。

    4-2.编写映射文件

    小提示我们要为Microsoft Visual Studio 2019添加编写NHibernate配置文件智能提示的功能。只要在下载的NHibernate里找到configuration.xsd和nhibernate-mapping.xsd两个文件并复制到X:Program Files (x86)Microsoft Visual Studio2019ProfessionalXmlSchemas目录即可。

    NHibernate要知道怎样去加载和存储持久化类的对象。这正是NHibernate映射文件发挥作用的地方。映射文件包含了对象/关系映射所需的元数据。元数据包含持久化类的声明和属性到数据库的映射。映射文件告诉NHibernate它应该访问数据库里面的哪个表及使用表里面的哪些字段。

    这里,我为Customer.cs类编写映射文件。在NHibernateOper.Repository项目的Mappings文件夹下新建xml,命名为Customer.hbm.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
       assembly="NHibernateOper.DomainModel"
    namespace="NHibernateOper.DomainModel">
        <class name ="Customer">
            <id name="CustomerId" column ="CustomerId">
                <generator class ="native"/>
            </id>
            <property name ="Firstname"/>
            <property name ="Lastname"/>
        </class>
    </hibernate-mapping>
    注意

    XML文件的默认生成操作为“内容”,这里需要修改为“嵌入的资源”生成,因为NHibernate是通过查找程序集中的资源文件映射实体,

    否则出现“ failed: NHibernate.MappingException : No persister for: NHibernateSample.Domain.Entities.Customer”异常。


    <generator class ="native"/>:依据底层数据库自动生成标识符的能力,来选择使用identity、sequence或hilo标识符生成器。它能自动判断底层DB提供的生成标识符的机制。
    generator节点中class其他参数选项及用法意义,查看这里

    5.编写数据访问层

    5-1.辅助类

    我们现在可以开始NHibernate了。首先,我们要从ISessionFactory中获取一个ISession(NHibernate的工作单元)。ISessionFactory可以创建并打开新的Session。一个Session代表一个单线程的单元操作。 ISessionFactory是线程安全的,很多线程可以同时访问它。ISession不是线程安全的,它代表与数据库之间的一次操作。ISession通过ISessionFactory打开,在所有的工作完成后,需要关闭。 ISessionFactory通常是个线程安全的全局对象,只需要被实例化一次。我们可以使用GoF23中的单例(Singleton)模式在程序中创建ISessionFactory。这个实例我编写了一个辅助类NHibernateHelper 用于创建ISessionFactory并配置ISessionFactory和打开一个新的Session单线程的方法,之后在每个数据操作类可以使用这个辅助类创建ISession 。

    在NHibernateOper.Utility项目中添加NHibernateHelper .cs

        public class NHibernateHelper
        {
            private ISessionFactory _sessionFactory;
            public NHibernateHelper()
            {
                _sessionFactory = GetSessionFactory();
            }
            private ISessionFactory GetSessionFactory()
            {
                return (new Configuration()).Configure().BuildSessionFactory();
            }
            public ISession GetSession()
            {
                return _sessionFactory.OpenSession();
            }
        }

    可以通过这种方式给类库添加NHibernate特定版本的引用 

    5-2.编写操作

    在Repository中新建一类CustomerOper.cs,编写一方法GetCustomerId用于读取客户信息。在编写方法之前,我们需要初始化Session。

            private NHibernateHelper helper = new NHibernateHelper();
            private ISession _session;
            public CustomerOper()
            {
                _session = helper.GetSession();
            }

    NHibernate有不同的方法来从数据库中取回对象。最灵活的方式是使用NHibernate查询语言(HQL),是完全基于面向对象的SQL。

     public void CreateCustomer(Customer customer)
            {
                _session.Save(customer);
                _session.Flush();
            }
            public Customer GetCustomerById(int customerId)
            {
                return _session.Get<Customer>(customerId);
            }

    6.编写数据访问层的测试

    6-1.配置NHibernate

    我们可以几种方法来保存NHibernate的配置,具体以后来介绍,这里我们使用hibernate.cfg.xml文件来配置,不过不必担心,这个文件我们可以在packagesNHibernate.5.3.0ConfigurationTemplatesMSSQL.cfg.xml文件夹下找到,直接复制到Repository中修改一下配置信息和文件输出属性就可以了。

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Add this element -->
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
            <!--配置数据库方言-->
            <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
            <!--配置数据库连接字符串-->
            <property name="connection.connection_string">
                Data Source=.;Initial Catalog=NHibernateOper;Persist Security Info=True;User ID=sa;Password=***********
            </property>
            <property name="proxyfactory.factory_class">
                NHibernate.Bytecode.DefaultProxyFactoryFactory,
                NHibernate
            </property>
    
            <mapping assembly="NHibernateOper.Repository" />
        </session-factory>
    </hibernate-configuration>
    注意

    hibernate.cfg.xml文件的默认“复制到输出目录”为“不复制”,这里需要修改为“始终复制”。否则出现“failed: NHibernate.Cfg.HibernateConfigException : An exception occurred during configuration of persistence layer. ----> System.IO.FileNotFoundException : 未能找到文件“NHibernateSampleNHibernateSample.Data.TestinDebughibernate.cfg.xml””异常。

    PS:(issues-su)
    1.hibernate.cfg.xml文件中各节点意义及用法,查看这里,hibernate.cfg.xml需要放在NHibernateSample.Data.Test的根目录下,不然读取不到

    6-2.测试

    好了,终于可以使用我们的方法了,这里新建一个测试类NHibernateOperFixture.cs来编写测试用例:调用CustomerOper类中GetCustomerId方法查询数据库中CustomerId为1的客户,判断返回客户的Id是否为1。

    [TestFixture]
    public class NHibernateOperFixture
    {
        private NHibernateSample _sample;
        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            _sample = new NHibernateSample();
        }
        [Test]
        public void GetCustomerByIdTest()
        {
            var tempCutomer = new Customer {FirstName = "", LastName = "永京"};
            _sample.CreateCustomer(tempCutomer);
            Customer customer = _sample.GetCustomerById(1);
            int customerId = customer.Id;
            Assert.AreEqual(1,customerId);
        }
    }

    我们使用Nunit测试一下这个方法:OK,测试通过。

    注意

    NHibernateOper.Test 项目类型为  .NET类库 Frameworks,相关NHibernate和Nunit测试,参考链接

    按照下图方式直接安装最新版Nunit即可

     -----------------***************---------------------

    结语(NHibernate Profiler一直配置不成功)

    注意

    HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();

    程序中加入上述语句之后就提示下方错误,mark下,下次解决

    System.Reflection.AmbiguousMatchException:“发现不明确的匹配。”
    此异常最初是在此调用堆栈中引发的:
    [外部代码]
    NHibernateSample.Domain.NHibernateHelper.GetSessionFactory() - 位于 NHibernateHelper.cs
    NHibernateSample.Domain.NHibernateHelper.NHibernateHelper() - 位于 NHibernateHelper.cs
    NHibernateSample.Web.Controllers.HomeController.HomeController() - 位于 HomeController.cs

    结语(NHibernate Profiler一直配置不成功)

    这里我使用NHibernate监视器NHibernate Profiler 查看结果:

    测试结果

    测试结果

    注意

    PS:
    假如你需要用NHibernate Profiler查看生成的sql语句,而你的项目是用VS2010建立的,那么需将项目的Framework改成3.5或3.0或2.0,若用Framework 4.0下会报“引发类型为“System.ExecutionEngineException”的异常。”异常,好像这是个Bug,详细查看这里(我使用的HibernatingRhinos.NHibernate.Profiler.Appender.dll-Version:0.9.0.1045)
    NHibernate Profiler的使用方法很简单,详细查看这里

    结语

    在这篇文章中,我们使用NHibernate来构建了一个最基本的项目,没有体现NHibernate更多细节,只描绘了NHibernate的基本面目。当然使用NHibernate有各种各样的程序架构,我按照一般模式构建的。请大家在实际项目中不要参考关于Session管理部分,本系列未做处理,更多实战知识以后介绍。


    • 参考:http://www.cnblogs.com/lyj/archive/2008/10/14/1310913.html

    上一篇:NHibernate之(1):开篇有益

    下一篇:NHibernate之(3):探索查询之NHibernate查询语言(HQL)

  • 相关阅读:
    WebUpLoder 能自动预览,能多实例,包括后台demo
    ajax请求总是进入Error里
    c#_1:后台post请求
    Echarts_1:水平柱体
    Hello World!
    python正则表达式
    python web.py出现ValueError: need more than 1 value to unpack
    web.py端口被占用的错误
    github commit时出现 Please tell me who you are.以及项目名称管理
    打飞机小游戏 python+pygame
  • 原文地址:https://www.cnblogs.com/a282421083/p/13425684.html
Copyright © 2011-2022 走看看