编程浪子的博客

碌碌无为终为过

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

休息两天半.打开博客园看到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; }
        }

    }
}
NHibernate持久化类的所有的public的属性必须声明为virtual
 
五、映射cat

Cat.hbm.xml映射文件包含了对象/关系映射(O/R Mapping)所需的元数据。元数据包含持久化类的声明和属性到数据库的映射(指向字段和其他实体的外键关联)。

请注意Cat.hbm.xml在Visual Stuido里面要设置为嵌入式资源(embedded resource),否则会报错。

新建一个xml文件名字为Cat.hbm.xml,添加如下内容:
<?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>
这里有一个标记挺有意思的:
<generator class="uuid.hex" />
他说明id字段是一个数据库标识符生成器,程序会自动产生一个32 hex character 用于标识一条数据
 
六、使用持久化管理器(ISession) ,写入数据
NHibernate的ISession了。它是一个 持久化管理器, 我们通过ISession来从数据库中存取Cat

首先,我们要从ISessionFactory中获取一个ISession(NHibernate的工作单元)。

ISessionFactory sessionFactory =
            new Configuration().Configure().BuildSessionFactory();
ISessionFactory代表一个数据库,并且使用一个XML配置文件(Web.config或者hibernate.cfg.xml)。 NHibernate通过对Configuration().Configure()的调用来装载配置文件,并初始化成一个Configuration实例。通过Configuration实例创建一个ISessionFactory。 在创建 ISessionFactory之前(它是不可变的),你可以访问Configuration来设置其他属性(甚至修改映射的元数据)。
ISessionFactory通常只是被初始化一次

下面实现了一个名为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
        }

七、读取数据:
和写入数据很像:
修改Default.aspx.cs里边的代码:
        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'INSERT INTO Cat (Name, Sex, Weight, Id) VALUES 
(@p0, @p1, @p2, @p3)',N'@p0 nvarchar(16),@p1 nchar(1),@p2 real,@p3 nvarchar(4000)',
@p0=N'pp',@p1=N'F',@p2=102,@p3=N'9b2337d79f54403ab78ff6198ec9f68b'

读取:
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语句  呵呵
Technorati 标签: NHibernate

 
posted on 2010-08-28 12:18  编程浪子_  阅读(1194)  评论(0编辑  收藏  举报