这个教程演示了如何在微软开发环境里搭建一个NHibernate 2.0.0例子. 使用了以下工具:
Internet 信息服务(IIS)管理器 - ASP.NET支持的Web服务器.
SQL Server 2005 - 数据库服务器. 这个例子里面使用的是桌面版本(EXPRESS), 可以从微软免费下载. NHibernate也支持其他数据库,更换数据库要做的仅仅是在配置文件里更改数据库方言和数据库驱动。
Visual Studio .NET 2005 - 开发环境.
首先,我们创建一个Web项目.项目命名为QuickStart。 项目会自动的创建一个http://localhost/QuickStart虚拟目录。
打开项目,添加NHibernate.dll引用。Visual Studio会自动的将你引用的库的这个库的依赖文件拷贝到你的输出目录. 如果你使用其他数据库,请添加对应的数据访问程序集到你的项目。
我们现在开始为NHibernate配置数据库连接信息。在这之前,打开项目里面自动生成的Web.config文件按照下面的方式添加一个配置元素:
class="code_img_closed" src="/Upload/Images/2014032318/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('5d9bdc25-5845-4731-845e-5ee0e73d9d9b',event)" src="/Upload/Images/2014032318/2B1B950FA3DF188F.gif" alt="" />1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- Add this element --> 4 <configSections> 5 <section 6 name="hibernate-configuration" 7 type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" 8 /> 9 </configSections> 10 11 <!-- Add this element --> 12 <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> 13 <session-factory> 14 <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property> 15 <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> 16 <property name="connection.connection_string"> 17 Server=(local);initial catalog=quickstart;Integrated Security=SSPI 18 </property> 19 <mapping assembly="QuickStart" /> 20 </session-factory> 21 </hibernate-configuration> 22 23 <!-- Leave the system.web section unchanged --> 24 <system.web> 25 ... 26 </system.web> 27 </configuration>web.config <configSections>在配置文件里定义了一个配置节并且声明了这个配置节里面的数据如何解析。
ISessionFactory在NHibernate里面是一个单个数据存储的概念(在SQLServer里面就是对应一个database),多数据库操作可以使用创建多个XML配置文件以及在程序里创建多个Configuration和 ISessionFactory对象来实现。
<hibernate-configuration>配置节的最后一个元素声明了 QuickStart作为包含持久化类以及对应映射文件所在的应用程序集名称。
映射文件包含POCO类映射到一个或者多个数据库表的元数据信息。
我们待会就会提到映射文件。
首先我们来写一个POCO类,然后为这个类写一个数据库映射文件。
NHibernate使用简单的.Net对象(Plain Old CLR Objects ,就是POCOs,有时候也称作Plain Ordinary CLR Objects)
这种编程模型来进行持久化,POCO类通过set和get属性 访问其内部成员变量,对外则隐藏了内部实现的细节(假若需要的话,NHibernate也可以直接访问其内部成员变量)。
1 namespace QuickStart 2 { 3 public class Cat 4 { 5 private string id; 6 private string name; 7 private char sex; 8 private float weight; 9 10 public Cat() 11 { 12 } 13 14 public virtual string Id 15 { 16 get { return id; } 17 set { id = value; } 18 } 19 20 public virtual string Name 21 { 22 get { return name; } 23 set { name = value; } 24 } 25 26 public virtual char Sex 27 { 28 get { return sex; } 29 set { sex = value; } 30 } 31 32 public virtual float Weight 33 { 34 get { return weight; } 35 set { weight = value; } 36 } 37 } 38 }实体类Cat.cs
NHibernate对属性使用的类型不加任何限制。
所有的.NET类型和原始类型(比如string,char和DateTime)都可以被映射,也包括.Net 集合(System.Collections)中的类。
你可以把它们映射成为值,值集合,或者与其他实体类相关联。
Id是一个特殊的属性,代表了这个类的数据库标识符(主键),对于类似于Cat这样的实体类我们强烈建议使用。
NHibernate也可以使用内部标识符,但这样我们会失去一些程序架构方面的灵活性。
持久化类不需要实现什么特别的接口,也不需要从一个特别的持久化根类继承下来。
NHibernate也不需要使用任何编译期处理,比如IL操作,它独立的使用.Net反射机制和运行时类增强(通过Castle.DynamicProxy2 library)。
所以不依赖于NHibernate(POJO的类不需要依赖NHibernate),我们就可以把POJO的类映射成为数据库表。
为了让上面提到运行时类增强功能生效,NHibernate持久化类的所有的public的属性必须声明为virtual。
Cat.hbm.xml映射文件包含了对象/关系映射(O/R Mapping)所需的元数据。
元数据包含持久化类的声明和属性到数据库的映射(指向字段和其他实体的外键关联)。
请注意Cat.hbm.xml在Visual Stuido里面要设置为嵌入式资源(embedded resource)。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 3 namespace="QuickStart" assembly="QuickStart"> 4 5 <class name="Cat" table="Cat"> 6 7 <!-- A 32 hex character is our surrogate key. It's automatically 8 generated by NHibernate with the UUID pattern. --> 9 <id name="Id"> 10 <column name="CatId" sql-type="char(32)" not-null="true"/> 11 <generator class="uuid.hex" /> 12 </id> 13 14 <!-- A cat has to have a name, but it shouldn' be too long. --> 15 <property name="Name"> 16 <column name="Name" length="16" not-null="true" /> 17 </property> 18 <property name="Sex" /> 19 <property name="Weight" /> 20 </class> 21 22 </hibernate-mapping>Cat.hbm.xml
每个持久化类都应该有一个标识属性(实际上,这个类只代表实体,而不是独立的值类型类, 后者会被映射称为实体对象中的一个组件)。
这个属性用来区分持久化对象:如果catA.Id.Equals(catB.Id)结果是true的话, 这两个Cat就是相同的。
这个概念称为数据库标识。
NHibernate附带了几种不同的标识符生成器, 用于不同的场合(包括数据库本地的顺序(sequence)生成器、hi/lo高低位标识模式、和程序自己定义的标识符)。
我们在这里使用UUID生成器(只在测试时建议使用,如果使用数据库自己生成的整数类型的键值更好), 并指定Cat表中的CatId字段(作为表的主键)存放生成的标识值。
Cat的其他属性都映射到同一个表的字段。
对Name属性来说, 我们把它显式地声明映射到一个数据库字段。
如果数据库schema是通过由映射声明自动生成的(作为SQL DDL指令)的话, 这就特别有用。
所有其它的属性都用NHibernate的默认值映射,大多数情况你都会这样做。
数据库中的Cat表看起来是这样的:
Column | Type | Modifiers
----------+------------------+----------------------
CatId | char(32) | not null, primary key
Name | nvarchar(16) | not null
Sex | nchar(1) |
Weight | real |
你现在可以在你的数据库中手工创建这个表了,如果你需要使用SchemaExport工具把这个步骤自动化,请参阅第 《17.工具箱指南》。
这个工具能够创建完整的SQL DDL,包括表定义,自定义的字段类型约束,惟一约束和索引。
如果使用使用的是SQLServer,请确保ASP.Net用户有权限访问该数据库。
我们现在可以开始使用NHibernate的ISession了。它是一个 持久化管理器, 我们通过ISession来从数据库中存取Cat。
首先,我们要从ISessionFactory中获取一个ISession(NHibernate的工作单元)。
1 ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
ISessionFactory代表一个数据库,并且使用一个XML配置文件(Web.config或者hibernate.cfg.xml)。
NHibernate通过对Configuration().Configure()的调用来装载配置文件,并初始化成一个Configuration实例。
通过Configuration实例创建一个ISessionFactory。
在创建 ISessionFactory之前(它是不可变的),你可以访问Configuration来设置其他属性(甚至修改映射的元数据)。
我们应该在哪儿创建ISessionFactory,在我们的程序中又如何访问它呢?
ISessionFactory通常只是被初始化一次,比如说在Application_Start事件里来初始化。 这意味着你不应该在ASP.NET页面中把它作为一个实例变量来持有,而应该放在其他地方。
进一步的说, 我们需要使用单例(Singleton)模式,我们才能更容易的在程序中访问 ISessionFactory。
下面的方法就同时解决了两个问题:对ISessionFactory的初始配置与便捷使用。
下面实现了一个名为NHibernateHelper的帮助类:
1 using System; 2 using System.Web; 3 using NHibernate; 4 using NHibernate.Cfg; 5 6 namespace QuickStart 7 { 8 public sealed class NHibernateHelper 9 { 10 private const string CurrentSessionKey = "nhibernate.current_session"; 11 private static readonly ISessionFactory sessionFactory; 12 13 static NHibernateHelper() 14 { 15 sessionFactory = new Configuration().Configure().BuildSessionFactory(); 16 } 17 18 public static ISession GetCurrentSession() 19 { 20 HttpContext context = HttpContext.Current; 21 ISession currentSession = context.Items[CurrentSessionKey] as ISession; 22 23 if (currentSession == null) 24 { 25 currentSession = sessionFactory.OpenSession(); 26 context.Items[CurrentSessionKey] = currentSession; 27 } 28 29 return currentSession; 30 } 31 32 public static void CloseSession() 33 { 34 HttpContext context = HttpContext.Current; 35 ISession currentSession = context.Items[CurrentSessionKey] as ISession; 36 37 if (currentSession == null) 38 { 39 // No current session 40 return; 41 } 42 43 currentSession.Close(); 44 context.Items.Remove(CurrentSessionKey); 45 } 46 47 public static void CloseSessionFactory() 48 { 49 if (sessionFactory != null) 50 { 51 sessionFactory.Close(); 52 } 53 } 54 } 55 }帮助类NHibernateHelper.cs
这个类不用考虑ISessionFactory,应为它被设置为static类型的,并且将ISessionhttp请求之中。
ISessionFactory是安全线程,可以由很多线程并发访问并获取到ISessions。
单个ISession不是安全线程对象,它只代表与数据库之间的一次操作。
ISession通过ISessionFactory获得并在所有的工作完成后关闭。
1 ISession session = NHibernateHelper.GetCurrentSession(); 2 3 ITransaction tx = session.BeginTransaction(); 4 5 Cat princess = new Cat(); 6 princess.Name = "Princess"; 7 princess.Sex = 'F'; 8 princess.Weight = 7.4f; 9 10 session.Save(princess); 11 tx.Commit(); 12 13 NHibernateHelper.CloseSession();获取ISession并在完成后关闭
在一个ISession中,每个数据库操作都是在一个事务(transaction)中进行的, 这样就可以隔离开不同的操作(甚至包括只读操作)。
我们使用NHibernate的ITransaction API来从底层的事务策略中(本例中是ADO.NET事务)脱身出来。
注意这个例子没有包含任何异常处理。
注意:
你可以随心所欲的多次调用NHibernateHelper.GetCurrentSession();,你每次都会得到同一个当前请求的Session。
不管是在你的Application_EndRequest代码中,或者在Application_EndRequest中还是在HTTP结果返回之前, 你都必须确保这个Session在你的数据库访问工作完成后关闭。
这样做还有一个好处就是可以容易的使用延迟装载(lazy initialization): ISession在渲染view层的时候仍然打开着的,所以你在遍历当前对象图的时候可以装载所需的对象。
NHibernate有不同的方法用来从数据库中取回对象。最灵活的方式就是使用NHibernate查询语言(HQL),这是一种容易学习的语言,是对SQL的面向对象的强大扩展
1 using(ITransaction tx = session.BeginTransaction()) 2 { 3 IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex"); 4 query.SetCharacter("sex", 'F'); 5 foreach (Cat cat in query.Enumerable()) 6 { 7 Console.Out.WriteLine("Female Cat: " + cat.Name); 8 } 9 tx.Commit(); 10 }使用HQL查询数据
Hibernate也提供一种面向对象的按条件查询API,可以执行简洁安全类型的查询。
当然,NHibernate在所有与数据库的交互中都使用IDbCommand和参数绑定。
你也可以使用NHibernate的直接SQL查询特性, 或者在特殊情况下从ISession获取一个原始的ADO.NET连接。
在这个短小的教程中,我们对NHibernate的浅尝即止。
请注意我们没有在例子中包含任何ASP.NET相关代码。
你必须自行编写ASP.NET Page,并插入合适你的NHibernate代码。
请记住NHibernate作为一个数据库访问层,是与你的程序紧密相关的。
通常情况下,所有其他层次都依赖持久机制。请确信你理解了这种设计的内涵
Q空间:http://778078163.qzone.qq.com
博客园:http://www.cnblogs.com/LonelyShadow