NHibernate Step by Step (一) Hello,NHibernate!
好了,今天我们正式开始NHibernate的历程,在第一次的练习中,我将尽量详细地讲解环境的配置,以后将不再详细解释。
基本的软件环境如下:
1.NHibernate www.nhibernate.org 当前版本是1.0.2
2.Code Smith http://www.codesmithtools.com/
3.NHibernate模板 点击这里下载
当然,少不了VS2005跟SQLServer了,我这里用的是SQLServer2005,教程用在SQLServer2000上应该没有问题,默认情况下,我将建立并使用一个叫NHibernate的数据库。
首先,我们先建立一个最简单的Person表,如下完整脚本(你可以进行修改以适合自己的数据库):
USE [NHibernate]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Person](
[id] [
int
] IDENTITY(
1
,
1
) NOT NULL,
[name] [varchar](
50
) COLLATE Chinese_PRC_CI_AS NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (IGNORE_DUP_KEY
=
OFF) ON [PRIMARY]
) ON [PRIMARY]
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
GO
SET ANSI_PADDING OFF
仅有两个字段,一个自动增长的id,一个name,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f3e03c07205edf687a45b4a1203ab869.jpeg)
然后将下载的nhibernate-template解压,打开Code Smith,将模板加入”Template Explorer”,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/51a603aca16e10fb1e8b2e83bbe79d6a.jpeg)
然后在其中的NHibernate.cst上点右键,选择“Execute”,弹出设置窗口,在左边的属性窗口进行如下设置:
![](https://i-blog.csdnimg.cn/blog_migrate/ba356e32f74fecc27c4dda445d67ee7c.jpeg)
注意:SourceDatabase属性在第一次选择时需要配置一个连接字符串,配置好后Code Smith将记录下来。 Assembly属性代表的是生成文件的默认Assembly名,而NameSpace,顾名思义,就是使用的命名空间了,这里我们全部使用”Test.Model”,请记住这个名字,点击左下角的Generate,将会在指定的输出目录下产生两个文件:Person.cs,Person.hbm.xml。
好了,NHibernate需要的类文件和映射文件生成完了,我们可以开始干活了!(生成NHibernate文件均是如此步骤,以后不再赘述)
新建立一个类库工程,为了简洁起见,我们命名为Model,需要注意的是,为了跟刚才生成的文件对应,我们需要在Model工程的属性页中将起Assembly名字设为上面的“Test.Model”,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/441d2216a4d568c5debf99600b6c8de3.jpeg)
然后将刚才生成的两个文件Person.cs和Person.hbm.xml加入到Model工程中来,选中Person.hbm.xml文件,在属性窗口中将其“Build Action”设置为“Embedded Resource”(这是非常重要的一步,否则NHibernate将无法找到映射文件),如下:
![](https://i-blog.csdnimg.cn/blog_migrate/7e64449d03c6b25340f7d371911822a6.jpeg)
build,ok,通过。
然后建立一个控制台工程,命名为Console1,添加NHibernate和上面Model项目的引用,另外添加一个应用程序配置文件,如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
configSections
>
<
section
name
="nhibernate"
type
="System.Configuration.NameValueSectionHandler, System,
Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</
configSections
>
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
<
nhibernate
>
<
add
key
="hibernate.connection.provider"
value
="NHibernate.Connection.DriverConnectionProvider"
/>
<
add
key
="hibernate.connection.driver_class"
value
="NHibernate.Driver.SqlClientDriver"
/>
<
add
key
="hibernate.connection.connection_string"
value
="Server=localhost;Initial Catalog=NHibernate;Integrated Security=SSPI"
/>
<
add
key
="hibernate.connection.isolation"
value
="ReadCommitted"
/>
<
add
key
="hibernate.dialect"
value
="NHibernate.Dialect.MsSql2000Dialect"
/>
</
nhibernate
>
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
</
configuration
>
然后编写如下代码:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
NHibernate;
using
NHibernate.Cfg;
using
Test.Model;
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
namespace
Console1
![](https://i-blog.csdnimg.cn/blog_migrate/3349e915d080ee7463bab5edd608c067.gif)
{
class Program
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
static void Main(string[] args)
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
Configuration config = new Configuration().AddAssembly("Test.Model");
ISessionFactory factory = config.BuildSessionFactory();
ISession session = factory.OpenSession();
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
Person person = new Person();
person.Name = "Jackie Chan";
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
ITransaction trans = session.BeginTransaction();
try
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
session.Save(person);
trans.Commit();
Console.WriteLine("Insert Success!");
}
catch (Exception ex)
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
trans.Rollback();
Console.WriteLine(ex.Message);
}
}
}
}
运行,ok,执行成功!!
我们到数据库检查一下,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/0938559206ed993f4679d0ec69d8b844.jpeg)
我们想要添加的记录已经成功加入到数据库中!!
是不是感觉有些神奇啊?好,我们开始详细解释。
先来看生成的两个文件,第一个是Person.cs,如下:
using
System;
using
System.Collections;
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
namespace
Test.Model
![](https://i-blog.csdnimg.cn/blog_migrate/3349e915d080ee7463bab5edd608c067.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/e830ed5f6da5a109938ce5c7a1bf0b27.gif)
Person#region Person
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
/**//// <summary>
/// Person object for NHibernate mapped table 'Person'.
/// </summary>
public class Person
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/e830ed5f6da5a109938ce5c7a1bf0b27.gif)
Member Variables#region Member Variables
protected int _id;
protected string _name;
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
#endregion
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e830ed5f6da5a109938ce5c7a1bf0b27.gif)
Constructors#region Constructors
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
public Person()
{ }
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
public Person( string name )
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
this._name = name;
}
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
#endregion
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e830ed5f6da5a109938ce5c7a1bf0b27.gif)
Public Properties#region Public Properties
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
public int Id
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
get
{return _id;}
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
set
{_id = value;}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
public string Name
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
get
{ return _name; }
set
![](https://i-blog.csdnimg.cn/blog_migrate/b54c49b55542a10c3d2c69579cdd806c.gif)
{
if ( value != null && value.Length > 50)
throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());
_name = value;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8e598fd576e1239cf8cc9aed45083d94.gif)
#endregion
}
#endregion
}
你可以发现,这完全是一个普通的poco类(Plain Old CLR Object),仅仅是对数据库person表的一个完全映射,不依赖于任何框架,可以用来作为持久化类,你可以在任何地方使用而不用担心依赖于某些神秘的运行时东西。
另外,NHibernate需要知道怎样去加载(load)和存储(store)持久化类的对象。这正是NHibernate映射文件发挥作用的地方。映射文件告诉NHibernate它应该访问数据库(database)里面的哪个表(table)及应该使用表里面的哪些字段(column),这就是我们今天要讲的重点了,Person.hbm.xml,如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.0"
>
<
class
name
="Test.Model.Person, Test.Model"
table
="Person"
>
<
id
name
="Id"
type
="Int32"
unsaved-value
="0"
>
<
column
name
="id"
sql-type
="int"
not-null
="true"
unique
="true"
index
="PK_Person"
/>
<
generator
class
="native"
/>
</
id
>
<
property
name
="Name"
type
="String"
>
<
column
name
="name"
length
="50"
sql-type
="varchar"
not-null
="true"
/>
</
property
>
</
class
>
</
hibernate-mapping
>
不用说,最顶层的hibernate-mapping节点是NHibernate用来进行映射的根了,其中,包含一个class节点,里面的name属性对应我们的Person类,注意,需要完整的限定名;而table属性,则显而易见是对应数据库中的Person表了。
我们再往里面看,分别有两个节点,一个是id,对应数据库中的id,一个是属性name,对应表中的column name和Person类中的name属性,整个映射文件简捷明了,一看即知。实际上这是由代码产生工具产生的映射文件,里面很多东西我们其实可以省略,如下写法:
<property name=”Name” column=”name” />
NHibernate将自动去匹配数据库中的列而不需要我们来设置。
下面,我们来看一下应用程序配置文件中都记录了那些东西,如下:
hibernate.connection.provider_class
定制IConnectionProvider的类型.
例如:full.classname.of.ConnectionProvider (如果提供者创建在NHibernate中), 或者 full.classname.of.ConnectionProvider, assembly (如果使用一个自定义的IConnectionProvider接口的实现,它不属于NHibernate)。
hibernate.connection.driver_class
定制IDriver的类型.
full.classname.of.Driver (如果驱动类创建在NHibernate中), 或者 full.classname.of.Driver, assembly (如果使用一个自定义IDriver接口的实现,它不属于NHibernate)。
hibernate.connection.connection_string
用来获得连接的连接字符串.
hibernate.connection.isolation
设置事务隔离级别. 请检查 System.Data.IsolationLevel 来得到取值的具体意义并且查看数据库文档以确保级别是被支持的。
例如: Chaos, ReadCommitted, ReadUncommitted, RepeatableRead, Serializable, Unspecified
hibernate.dialect
NHibernate方言(Dialect)的类名 - 可以让NHibernate使用某些特定的数据库平台的特性
例如: full.classname.of.Dialect(如果方言创建在NHibernate中), 或者full.classname.of.Dialect, assembly (如果使用一个自定义的方言的实现,它不属于NHibernate)。
接着,我们开始解释代码的执行,如下:
Configuration config
=
new
Configuration().AddAssembly(
"
Test.Model
"
);
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
//
通过配置对象来产生一个SessionFactory对象,这是一个Session工厂,
//
那么Session是用来干什么的呢?一个Session就是由NHibernate封装
//
的工作单元,我们可以近似地认为它起到ADO.Net中Connection的作用。
ISessionFactory factory
=
config.BuildSessionFactory();
ISession session
=
factory.OpenSession();
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
Person person
=
new
Person();
person.Name
=
"
Jackie Chan
"
;
![](https://i-blog.csdnimg.cn/blog_migrate/7dd64e5cf98f42169c83c913db047181.gif)
//
这里,开启一个由NHibernate封装的事务,当然,在这里最终代表
//
的还是一个真实的数据库事务,但是我们已经不需要再区分到底是
//
一个SqlTransaction还是一个ODBCTransaction了
ITransaction trans
=
session.BeginTransaction();
try
![](https://i-blog.csdnimg.cn/blog_migrate/3349e915d080ee7463bab5edd608c067.gif)
{
//保存,提交,就这么简单!!
session.Save(person);
trans.Commit();
Console.WriteLine("Insert Success!");
}
catch
(Exception ex)
![](https://i-blog.csdnimg.cn/blog_migrate/3349e915d080ee7463bab5edd608c067.gif)
{
trans.Rollback();
Console.WriteLine(ex.Message);
}
现在有了一个基本的概念了吧??
好了,第一篇就讲这么多,我们下次再接着练习。
Step by Step,顾名思义,是一步一步来的意思,整个教程我将贯彻这一理念,待此系列结束后,我们再就某些高级话题进行深入。