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 FilesMicrosoft Visual Studio 9.0XmlSchemas文件夹就可以。

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文件来配置,只是不必操心,这个文件我们能够在srcNHibernate.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 : 未能找到文件“NHibernateSampleNHibernateSample.Data.TestinDebughibernate.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管理部分。本系列未做处理。很多其它实战知识以后介绍。

原文地址:https://www.cnblogs.com/wgwyanfs/p/6866236.html