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.测试
- 结语
开始使用NHibernate
我们亲自动手,一步一步搭建一个NHibernate程序来,我以一个实际场景电子交易程序来模拟,客户/订单/产品的经典组合。由于是第一次使用NHibernate,所以我们的目的是映射一张表并完成使用NHibernate来读取数据,下面的一幅图片给了我们第一印象。我们按照基本开发软件思想的流程一步一步完成。
我使用的开发环境:Microsoft Visual Studio 2008 SP1、SQL Server 2008 Express、NHibernate 2.1.1GA。
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学习教程(2)-- 第一个NHibernate程序的更多相关文章
- C#.NET学习笔记2---C#.第一个C#程序
C#.NET学习笔记2---C#.第一个C#程序 技术qq交流群:JavaDream:251572072 教程下载,在线交流:创梦IT社区:www.credream.com 6.第一个C#程序: ...
- Spark学习笔记1——第一个Spark程序:单词数统计
Spark学习笔记1--第一个Spark程序:单词数统计 笔记摘抄自 [美] Holden Karau 等著的<Spark快速大数据分析> 添加依赖 通过 Maven 添加 Spark-c ...
- Nhibernate学习教程(1)-- 开篇有益
NHibernate之旅(1):开篇有益 本节内容 NHibernate是什么 NHibernate的架构 NHibernate资源 欢迎加入NHibernate中文社区 作者注:2009-11-06 ...
- <CPP学习>第一天 第一个CPP程序 hello word
由于我是计算机类嵌入式专业的大一学生,之前一直使用的是生万物的C语言,了解了其过程性语言的特性及其基础语法,在大一下学期期末阶段想自学一下C++,其实在开学初就买了一本C++ Primer,但由于各种 ...
- Java学习 1.4——第一个Java程序:Hello World!
这一篇一起来写第一个Java程序,同时也了解一下IDEA的使用: 打开IDEA,新建项目: 选择Java,右边project SDK是选择Java版本,上一篇我们自己安装了JDK1.8,IDEA自带一 ...
- OD学习笔记10:一个VB程序的加密和解密思路
前边,我们的例子中既有VC++开发的程序,也有Delphi开发的程序,今天我们给大家分析一个VB程序的加密和解密思路. Virtual BASIC是由早期DOS时代的BASIC语言发展而来的可视化编程 ...
- c++学习笔记---04---从另一个小程序接着说
从另一个小程序接着说 文件I/O 前边我们已经给大家简单介绍和演示过C和C++在终端I/O处理上的异同点. 现在我们接着来研究文件I/O. 编程任务:编写一个文件复制程序,功能实现将一个文件复制到另一 ...
- [No0000120]Python教程3/9-第一个Python程序
现在,了解了如何启动和退出Python的交互式环境,我们就可以正式开始编写Python代码了. 在写代码之前,请千万不要用“复制”-“粘贴”把代码从页面粘贴到你自己的电脑上.写程序也讲究一个感觉,你需 ...
- 【Python】Django学习一:第一个Django程序
项目开发环境 Python 3.6 Django 1.11.5 Django安装 在开始安装Django之前,Django更新比较频繁,所以要选择合适的版本,这里选择Django1.11.5. pip ...
随机推荐
- “军装照”背后——天天P图如何应对10亿流量的后台承载。
WeTest 导读 天天P图"军装照"活动交出了一份10亿浏览量的答卷,一时间刷屏朋友圈,看到这幕,是不是特别想复制一个如此成功的H5?不过本文不教你如何做一个爆款H5,而是介绍天 ...
- C# 获取并判断操作系统版本,解决Win10、 Windows Server 2012 R2 读取失败的方案
Windows 8.1, Win10之后,通过GetVersion and GetVersionEx 方法获取WIndows操作系统版本号的功能需要添加manifest文件后才能查找到,不然的话会查找 ...
- 一个UITableViewCell的简单动画效果
实现下面UITableViewDelegate的方法: forRowAtIndexPath:(NSIndexPath *)indexPath{ CATransform3D rotation; rota ...
- RabbitMQ安装以及java使用(二)
上一篇记录了rabbitmq的安装,这一篇记录一下rabbitmq的java客户端的简单使用,当然在项目中我们有更为复杂的应用场景,这里只有最简单的点对点生产者与消费者模式. 1.建立工程 首先建立一 ...
- JavaScript实现的--贪吃蛇
总的实现思路: 一.效果部分: 1.编写html代码,加上样式. 二.JavaScript部分: 1.利用dom方法创建一块草坪,即活动区域: 2.创建一条蛇,并设置其初始位置: ...
- Oracle 11.2.0.1 ADG环境MRP进程遭遇ORA-600异常终止
环境:Linux + Oracle 11.2.0.1 ADG 现象:发现备库没有应用日志 1. 数据库查询备库目前状态 发现备库目前没有应用日志,apply lag已经显示备库有3天21小时多没有应用 ...
- 接口的作用(C#)
C#中的接口(Interface)对于很多初学者来说是个很容易迷糊的东西,使用起来很简单,无非就是定义接口,接口里面包含一些属性.索引器.事件和一些没有修饰符的方法,也没有方法的具体实现代码:然后在类 ...
- 设计模式(4)--AbstractFactory(抽象工厂模式)--创建型
1.模式定义: 抽象工厂是应对产品族概念的,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类 2.模式特点: 抽象工厂模式为创建一组对象提供了一种解决方案.与工厂方法模式相比,抽象工 ...
- 【Linux】Apache Httpd 服务管理
基本的操作方法: 本文假设你的apahce安装目录为/usr/local/apache2,这些方法适合任何情况 apahce启动命令: 推荐 [user@master1 ~]$ /usr/local ...
- C# 实例练习——字符串处理(第三天)
1. 编写程序将IP地址分解后输出(将IP地址中的点(.)去掉,替换成空格符),如:132.123.4替换后为132 123 4. Console.WriteLine("请输入您电脑 ...