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

    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.测试
    • 结语

    作者注:2009-11-06已更新

    开始使用NHibernate

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

    我使用的开发环境:Microsoft Visual Studio 2008 SP1、SQL Server 2008 Express、NHibernate 2.1.1GA。

    ORM

    1.获取NHibernate

    使用官方2009年10月31日最新发布的NHibernate-2.1.1.GA版本。如果你第一次使用NHibernate,先到这里下载NHibernate最新版本(包括源码、发布版本、参考文档、API文档,可选择下载)。如果用到NHibernate的扩展项目到这里下载获得NHibernate Contrib最新版本。NHibernate-2.1.1.GA是.NET2.0平台的最后一个版本,关于NHibernate-2.1.1.GA的更多信息请点击这里

    关于NHibernate2.1版本的一些说明:

    NHibernate2.1版本改变了ByteCode延迟加载机制,有三种3种IoC框架动态代理方式,分别为:Castle框架、LinFu框架、Spring.Net框架。我们只要选择一种,在配置文件中配置proxyfactory.factory_class节点。

    如果使用Castle.DynamicProxy2动态代理,引用NHibernate.ByteCode.Castle.dll程序集并配置proxyfactory.factory_class节点为<property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory,NHibernate.ByteCode.Castle</property>

    如果使用LinFu.DynamicProxy动态代理,引用NHibernate.ByteCode.LinFu.dll程序集并配置proxyfactory.factory_class节点为<property name="proxyfactory.factory_class"> NHibernate.ByteCode.LinFu.ProxyFactoryFactory,NHibernate.ByteCode.LinFu</property>

    如果使用Spring.Aop动态代理,引用NHibernate.ByteCode.Spring.dll程序集并配置proxyfactory.factory_class节点为<property name="proxyfactory.factory_class"> NHibernate.ByteCode.Spring.ProxyFactoryFactory,NHibernate.ByteCode.Spring</property>

    另外NHibernate2.1要求.NET2.0 SP1以上版本 (System.DateTimeOffset),请使用VS2005的,务必打上Sp1补丁。推荐使用VS2008以上版本。

    2.建立数据库表

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

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

    数据库模型

    3.创建C#类库项目

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

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

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

    目录结构

    创建项目,结构如下:

    项目结构

    • Domain(领域模型):用于持久化类和O/R Mapping操作
    • Data(Data Access Layer数据访问层):定义对象的CRUD操作
    • Data.Test(数据访问层测试):对数据访问层的测试,这里我使用Nunit单元测试框架
    • Web:Web页面(这篇文章中暂未实现,请参考我的博客其他文章)
    项目引用
    • Domain:引用Iesi.Collections.dll程序集(Set集合在这个程序集中)和Castle动态代理
    • Data:引用NHibernate.dll和Iesi.Collections.dll程序集和动态代理相关程序集,Domain引用
    • Data.Test:引用NHibernate.dll和Iesi.Collections.dll程序集,nunit.framework.dll程序集(测试框架),Domain和Data引用

    4.设计Domain

    4-1.编写持久化类

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

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

    namespace NHibernateSample.Domain.Entities
    {
        public class Customer
        {
            public virtual int Id { 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 2008添加编写NHibernate配置文件智能提示的功能。只要在下载的NHibernate里找到configuration.xsd和nhibernate-mapping.xsd两个文件并复制到X:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas目录即可。

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

    这里,我为Customer.cs类编写映射文件。新建一XML文件,命名为Customer.hbm.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
       assembly="NHibernateSample.Domain"
       namespace="NHibernateSample.Domain.Entities">
      
      <class name ="Customer">
        <id name="Id" column ="CustomerId">
          <generator class ="native"/>
        </id>
        <property name ="FirstName"/>
        <property name ="LastName"/>
      </class>
    </hibernate-mapping>
    注意 XML文件的默认生成操作为“内容”,这里需要修改为“嵌入的资源”生成,因为NHibernate是通过查找程序集中的资源文件映射实体,使用.NET Reflector查看程序集:
    查看程序集
    否则出现“ failed: NHibernate.MappingException : No persister for: NHibernateSample.Domain.Entities.Customer”异常。

    5.编写数据访问层

    5-1.辅助类

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

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

    5-2.编写操作

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

    protected ISession Session { get; set; }
    public NHibernateSample(ISession session)
    {
        Session = session;
    }

    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文件来配置,不过不必担心,这个文件我们可以在src\NHibernate.Config.Templates文件夹下找到,直接复制到Data.Test中修改一下配置信息和文件输出属性就可以了。

    <?xml version="1.0" encoding="utf-8"?>
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
        <session-factory>
            <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
            <property name="connection.connection_string">
                Data Source=.\SQLEXPRESS;Initial Catalog=NHibernateSample;
          Integrated Security=True;Pooling=False
            </property>
            <property name="adonet.batch_size">10</property>
            <property name="show_sql">true</property>
            <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
            <property name="use_outer_join">true</property>
            <property name="command_timeout">10</property>
            <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
         <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, 
          NHibernate.ByteCode.Castle</property>
        <mapping assembly="NHibernateSample.Domain"/>    
        </session-factory>
    </hibernate-configuration>
    注意 XML文件的默认“复制到输出目录”为“不复制”,这里需要修改为“始终复制”。否则出现“failed: NHibernate.Cfg.HibernateConfigException : An exception occurred during configuration of persistence layer. ----> System.IO.FileNotFoundException : 未能找到文件“NHibernateSample\NHibernateSample.Data.Test\bin\Debug\hibernate.cfg.xml””异常。

    6-2.测试

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

    [TestFixture]
    public class NHibernateSampleFixture
    {
        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);
        }
    }

    我们使用TestDriven.NET测试一下这个方法:OK,测试通过。这里我使用NHibernate监视器NHibernate Profiler查看结果:

    测试结果

    测试结果

    结语

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

    NHibernate Q&A

    下次继续分享NHibernate!

  • 相关阅读:
    EBS SQL > Form & Report
    oracle sql 优化分析点
    MRP 物料需求计划
    MRPII 制造资源计划
    Barcode128 应用实务
    Oracle SQL语句优化技术分析
    APPSQLAP10710 Online accounting could not be created. AP Invoice 无法创建会计分录
    Oracle数据完整性和锁机制
    ORACLE Responsibility Menu Reference to Other User
    EBS 常用 SQL
  • 原文地址:https://www.cnblogs.com/lyj/p/1310913.html
Copyright © 2011-2022 走看看