休息两天半.打开博客园看到NHibernate专题.比较迷茫,俺可是ORM是什么都不知道的那种菜鸟.
本篇基本上是从菜鸟的角度构建的一个NHibernate的QuickStart:将一条数据写入数据库.
参看:李永京 NHibernate之旅系列第二篇和http://www.cnblogs.com/kiler的NHibernate2.0文档的非官方汉化版本.
李老人家的版本比较高深,一直不成功.太大了,感觉不是和我这样的菜菜.于是又参看http://www.cnblogs.com/kiler汉化的NHibernate2.0文档.
有那么个意思,挺好懂的!不过NHibernate2.0文档上的配置不全,运行时会报
The ProxyFactoryFactory was not configured.
ProxyFactoryFactory 没有设置!
下变是我构建第一个NHibernate的过程:
下载:https://sourceforge.net/projects/nhibernate/files/
我用的是最新版3.0Alpha2版,刚下的
一、首先:数据库部分.
在数据库中创建一个表Cat,创建脚本如下:
CREATE TABLE [dbo].[Cat]( [ID] [char](32) NOT NULL, [Name] [nvarchar](50) NULL, [Sex] [nchar](10) NULL, [Weight] [real] NULL, CONSTRAINT [PK_Cat] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
创建一个用于实验的表.我没有用李老的表,那个表比较复杂,还要涉及到表间的关系什么的!
二、创建一个WebApplication
我没有用李老那种方法:创建一个类库,然后编写NUnit测试。我NUnit比较生,昨天晚上看代码才知道是干什么用的!在Cnblog上找了篇文章看了一晚上才理解NUnit的用法。为了省事,干脆,用WebApplication承载我的实验,所有东西都放到里边去!
创建号这个WebApplication:NHibernateQuickStart
之后添加对NHibernate.dll和NHibernate.ByteCode.Castle.dll的引用.
三、配置Web.Config
首先在web.config中添加一个配置元素
<configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" /> </configSections>
设置一下:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <property name="connection.connection_string"> Server=(local);initial catalog=quickstart;Integrated Security=SSPI
</property>
<mapping assembly="QuickStart" />
</session-factory>
</hibernate-configuration>
这里有几个属性没有设置,运行时会报错:
The ProxyFactoryFactory was not configured.
参看李老的:
在这里加入了如下配置快:注册NHibernate.ByteCode.Castle.ProxyFactoryFactory
<property name="adonet.batch_size">10</property> <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle </property>
最终的Webconfig如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- Add this element --> <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" /> </configSections> <!-- Add this element --> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <property name="connection.connection_string"> Server=(local);initial catalog=quickstart;Integrated Security=SSPI </property> <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle </property> <mapping assembly="QuickStart" /> </session-factory> </hibernate-configuration>
<!-- Leave the system.web section unchanged --> <system.web> ... </system.web> </configuration>
NHibernate使用简单的.Net对象(Plain Old CLR Objects ,就是POCOs,有时候也称作Plain Ordinary CLR Objects)这种编程模型来进行持久化,POCO类通过set和get属性 访问其内部成员变量,对外则隐藏了内部实现的细节(假若需要的话,NHibernate也可以直接访问其内部成员变量)。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace NHibernateQuickStart { public class Cat { private string id; private string name; private char sex; private float weight; public Cat() { } public virtual string Id { get { return id; } set { id = value; } } public virtual string Name { get { return name; } set { name = value; } } public virtual char Sex { get { return sex; } set { sex = value; } } public virtual float Weight { get { return weight; } set { weight = value; } } } }
Cat.hbm.xml映射文件包含了对象/关系映射(O/R Mapping)所需的元数据。元数据包含持久化类的声明和属性到数据库的映射(指向字段和其他实体的外键关联)。
请注意Cat.hbm.xml在Visual Stuido里面要设置为嵌入式资源(embedded resource),否则会报错。
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernateQuickStart" assembly="NHibernateQuickStart"> <class name="Cat" table="Cat"> <!-- A 32 hex character is our surrogate key. It's automatically generated by NHibernate with the UUID pattern. --> <id name="Id"> <column name="Id" sql-type="char(32)" not-null="true"/> <generator class="uuid.hex" /> </id> <!-- A cat has to have a name, but it shouldn' be too long. --> <property name="Name"> <column name="Name" length="16" not-null="true" /> </property> <property name="Sex" /> <property name="Weight" /> </class> </hibernate-mapping>
他说明id字段是一个数据库标识符生成器,程序会自动产生一个32 hex character 用于标识一条数据
首先,我们要从ISessionFactory中获取一个ISession(NHibernate的工作单元)。
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
下面实现了一个名为NHibernateHelper的帮助类:
using System; using System.Web; using NHibernate; using NHibernate.Cfg; namespace QuickStart { public sealed class NHibernateHelper { private const string CurrentSessionKey = "nhibernate.current_session"; private static readonly ISessionFactory sessionFactory; static NHibernateHelper() { sessionFactory = new Configuration().Configure().BuildSessionFactory(); } public static ISession GetCurrentSession() { HttpContext context = HttpContext.Current; ISession currentSession = context.Items[CurrentSessionKey] as ISession; if (currentSession == null) { currentSession = sessionFactory.OpenSession(); context.Items[CurrentSessionKey] = currentSession; } return currentSession; } public static void CloseSession() { HttpContext context = HttpContext.Current; ISession currentSession = context.Items[CurrentSessionKey] as ISession; if (currentSession == null) { // No current session return; } currentSession.Close(); context.Items.Remove(CurrentSessionKey); } public static void CloseSessionFactory() { if (sessionFactory != null) { sessionFactory.Close(); } } } }
这个类不用考虑ISessionFactory,应为它被设置为static类型的,并且将ISessionhttp请求之中。
ISessionFactory是安全线程,可以由很多线程并发访问并获取到ISessions。 单个ISession不是安全线程对象,它只代表与数据库之间的一次操作。 ISession通过ISessionFactory获得并在所有的工作完成后关闭。
在程序自动添加的页面Default.aspx的CodeBehind文件Default.aspx.cs里边添加代码,操作数据库中的Cat表
protected void Page_Load(object sender, EventArgs e) { ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); Cat p = new Cat(); p.Name = "pp"; //不管数据库中是否允许ID为空,都不需要设置ID,设置了也没用。。。。。 p.Sex = 'F'; p.Weight = 102f; session.Save(p); //将p保存到数据库里边 //session.Load(p, "5f649160704f4688a1cdf1c1893877a9"); tx.Commit(); NHibernateHelper.CloseSession(); //关闭Session }
和写入数据很像:
protected void Page_Load(object sender, EventArgs e) { ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); Cat p = new Cat(); p.Name = "pp"; p.Sex = 'F'; p.Weight = 102f; //session.Save(p); session.Load(p, "5f649160704f4688a1cdf1c1893877a9"); 刚才写入数据时生成的ID,需要手动从数据库里边拷贝出来。。 tx.Commit(); NHibernateHelper.CloseSession(); Response.Write(p.Name); }
总结:
至此,俺的第一个NHibernate程序在拷贝和粘贴中完成了。NHibernate是你不用再直接跟ADO.Net打交道了,不用刻意去房子SQL语句的写法什么的了.
更多功能,有待俺继续探索
更新数据库,或读取数据库时,NHibernate是怎样操作数据的呢?
贴两个SqlServerProfiler监视到的Sql语句:
插入:
读取:
exec sp_executesql N'SELECT cat0_.Id as Id0_0_, cat0_.Name as Name0_0_,
cat0_.Sex as Sex0_0_, cat0_.Weight as Weight0_0_ FROM Cat cat0_ WHERE
cat0_.Id=@p0',N'@p0 nvarchar(4000)',@p0=N'9b2337d79f54403ab78ff6198ec9f68b'
更新:
exec sp_executesql N'UPDATE Cat SET Name = @p0, Sex = @p1, Weight = @p2
WHERE Id = @p3',N'@p0 nvarchar(16),@p1 nchar(1),@p2 real,@p3 nvarchar(4000)',
@p0=N'ddddddd',@p1=N'F',@p2=102,@p3=N'9b2337d79f54403ab78ff6198ec9f68b'
都是些很简单的SQL语句 呵呵