[翻译]NHibernate1.2.0文档学习(1)-QuickStart例子

序言
在如今的企业环境中,面向对象软件和一个关系型数据库一起工作是麻烦的和耗费时间的。Nhibernate是一个在.NET平台下的ORM工具。这个ORM团队描述说这是一个转换对象模型的数据到一个基于SQL架构的关系型数据模型的映射数据方法。
NHibernate不但关注.NET类到数据库表的映射(也可以说是.NET数据类型到SQL数据类型),同时提供了数据查询和检索工具。更重要的是它比使用SQL和ADO.NET进行手工处理减少了开发时间。
NHibernate的目标是让开发者从通常的数据持久化相关的编程工作中释放出来。对于那些以数据为中心,在数据库中只以存储过程去实现业务逻辑的应用程序,NHibernate并不是最好的,但是在基于.NET的中间层中的面向对象领域模型和业务逻辑是非常有用的。NHibernate能帮助你移除或封装指定的SQL代码,同时在通常的操作下,将数据中列表式转化为对象。


使用IIS和Microsoft SQL Server快速起步
1.1 开始NHibernate
这个教程描述了在Microsoft环境下尽心设置NHibernate 1.0.2。教程中使用的工具如下:
 Microsoft Internet Information Services(IIS) – web服务器支持ASP.NET。
 Microsoft SQL Server 2000 – 数据库服务器。本教程使用桌面版(MSDE),微软提供的一个免费版本。它也支持其它数据库,只需改变NHibernate SQL 方言和驱动配置。
 Micorsoft Visual Studio .NET 2003 – 开发环境。
首先,我们创建一个新的web工程。我们取名QuickStart,该工程的虚拟目录为http://localhost/QuickStart。在这个工程中,添加NHibernate.dll。Visual Studio将自动复制类库和它的依赖项到该工程的输出目录。如果你使用一个不同与SQL Server的数据库,在该工程的驱动程序中添加一个引用。
我们现在设置使用NHibernate进行数据库连接的配置信息。首先,打开该工程自动产生的wb.config文件,把下面的配置信息添加到文件中。
<?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.MsSql2000Dialect</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>

    <!-- Leave the system.web section unchanged -->
    <system.web>
        ...
    </system.web>
</configuration>
元素<configSections>包含了项的定义信息,后续处理者使用它来处理它们的内容。我们申明了一个<hibernate-configuration>,它通知Nhibernate程序使用Microsoft SQL Server 2000数据库和使用指定的连接串连接到数据库。方言(dialect)是必须设置的,因为不同的数据库对SQL语句的解释是不同的。Nhibernate关注这些不同点,并针对不同的主流商业数据库和开源数据库设定了不同的方言。
 在Nhibernate中,一个ISessionFactory代表了单个数据库。如果你想在你的应用程序中使用多个数据库,你可以创建多个XML配置文件,创建多个配置项和ISessionFactory对象。
 <hibernate-configuration>中最后申明的QuickStart做为包含类描述和映射文件的程序集的名称。这个映射文件包含了从POCO类到对应的一个数据库表(或多个表)的映射信息。接下来,让我们先来看看POCO类和对应到这个类的映射文件。

1.2 第一个持久类
在使用Nhibernate时,最好使用简单的CLR对象(POCOs,Plain Old CLR Objects)作为持久类。一个POCO类通过使用.NET的标准的属性机制,可以实现数据访问性控制,在公开接口的情况下,又能隐藏内部数据。
namespace QuickStart
{
    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并没有限制属性的类型,所有的.NET类型,原始类型(比如string,char和DateTime)和来自System.Collections命名空间的类都可以做为映射的类型。你可以把它们映射为值,值的集合,或关联到其它实体。Id是一个特别的属性,它是这个类的数据库标识(主键),这是强烈推荐的。我们可以不在类中申明标识符,Nhibernate将使用内部的标识,但是这样我们的应用程序架构将失去一些灵活性。
 我们不需要让持久化类去实现某个接口,或者继承自某个根持久化类。Nhibernate不在编译时处理,比如IL操作。它唯一依赖.NET反射和运行时类强化(通过Castle.DynamicProxy)。因此,通过Nhibernate,我们能把POCO类中的任何关系映射到数据表中。
 为了让上面所说的运行时类强化实现工作,Nhibernate需要所有的实体类的工作属性声明为virtual。


1.3映射Cat
Cat.hbm.xml映射文件包含了对象关系映射所需的元数据。这个元数据包含了持久化类的申明和映射到数据库表的属性(列和关联到其它实体的外键)。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="QuickStart" assembly="QuickStart">

    <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="CatId" 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>
每一个持久化类应该有一个标识特性(attribute)(实际上,只是类去表现实体,实体没有依赖值对象,值对象被映射为实体的一部分)。这个属性是用来区分持久化对象:如果CatA.Id.Equals(CatB.Id)返回true,那么这两个cat是相等的,这个被称为数据库标识。Nhibernate内置了多种针对不同场景的标识符产生器(包括产生数据库序列的native,产生表示表的hi/lo和应用程序分配标识符)。我们使用UUID产生器(只为测试目的,像数据库的整数代理键产生器)和指定表Cat中的列CatID为Nhibernate标识产生器产生的值(作为表的主键)。
Cat的所有其它属性是被映射到同一张表。我们在映射Name属性中使用显示的数据库列声明。当我们使用Nhibernate的SchemaExport工具产生映射文件,并根据这个映射文件自动产生数据库架构的情况是特别有用的。其它所有的属性使用默认值进行映射,它需要耗费你的多数时间。Cat数据库表结构如下:
Column |     Type     | Modifiers
--------+--------------+----------------------
 CatId  | char(32)     | not null, primary key
 Name   | nvarchar(16) | not null
 Sex    | nchar(1)     |
 Weight | real         |
 你现在应该手工创建数据库及表,如果你想自动完成这一步,你可以使用SchemaExport工具,你可以读第十六章,工具集向导。这个工具可以创建一个完全的SQL DDL,包括表定义,自定义列类型约束,唯一性约束和索引。如果你使用SQL Server,你应该确保ASPNET用户有权限操作数据库。

1.4运行工程
 我们现在开始使用Nhibernate的ISession。ISession是持久化对象管理接口,我们使用它存储Cats到数据库和从数据库中检索Cats。但是,我们必须先从ISessionFactory得到一个ISession(Nhibernate的工作单元):
ISessionFactory sessionFactory =
            new Configuration().Configure().BuildSessionFactory();
 一个ISessionFactory负责一个数据库,并且它只能使用一个XML配置文件(Web.config或hibernate.Cfg.xml)。在创建ISessionFactory(它是不可变的)之前,你可以通过访问Configuration类来设置其它属性(甚至改变映射元数据)。我们在那里创建ISessionFactory?在我们的应用程序中我们怎么样访问它?
 一个ISessionFactory通常只创建一次,比如:启动时在Application_Start事件处理中。这意味着在ASP.NET页面中,你不应该保持它在实例变量中,而是应该保存在其它位置。并且,我们需要各种单件模式,这样我们能在应用程序代码中很容易的访问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,而且还保留了当前HTTP请求的ISession。
 一个ISessionFactory是线程安全的,多个线程能并发的访问它和请求ISessions。一个ISession不是线程安全的,它代表了与数据库关联的单个工作单元。ISessions是通过ISessionFactory打开,并当所有工作结束后进行关闭。
ISession session = NHibernateHelper.GetCurrentSession();

ITransaction tx = session.BeginTransaction();

Cat princess = new Cat();
princess.Name = "Princess";
princess.Sex = 'F';
princess.Weight = 7.4f;

session.Save(princess);
tx.Commit();

NHibernateHelper.CloseSession();
 在一个ISession,每一个数据库操作发生在一个事务内,这样可以隔离每个数据库操作(甚至是Read-only操作)。我们使用Nhibernate的Itransaction API去抽象根本的事务策略(在我们这里,就是ADO.NET事务)。请注意:这个例子没有处理任何异常。
 同时请注意:你通过调用NhibernateHelper.GetCurrentSession();正如你所想的,你将得到HTTP请求的当前连接。当你的单元工作完成了以后,你必须确保在应用程序类的Application_EndRequest事件处理程序或在HTTP相应被发送以前的HttpModule中去关闭ISession。接下来的非常好的边缘效应是简单的延迟初始化:当界面呈现后,ISession是仍然打开的,因此当你定位到目标时,Nhibernate可以加载未初始化对象。
 Nhibernate有多种方法用于从数据库检索数据。最灵活的方法是通过Hibernate Query Language(HQL),这个语言是容易学习和对SQL的强大的面向对象扩展。
ITransaction tx = session.BeginTransaction();

IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex");
query.SetCharacter("sex", 'F');
foreach (Cat cat in query.Enumerable())
{
    Console.Out.WriteLine("Female Cat: " + cat.Name);
}

tx.Commit();
Nhibernate通过标准API提供了面向对象查询,这个标准API用来格式化类型安全的查询。Nhibernate通过使用IdbCommands和参数绑定到所有的SQL信息中。你也能使用Nhibernate的直接SQL查询或者从ISession中得到一个原始的ADO.NET连接。


1.5总结
在这个小教程中,我们只能浏览到Nhibernate的很小一部分的功能。请注意:我们并没有包含任何ASP.NET代码。你必须创建一个ASP.NET页,然后插入Nhibernate。
请记住,Nhibernate做为一个数据访问层,是紧紧集成到你的应用程序中。通常,所有其它的层,依赖持久化机制。你必须确保了解设计的含意。

posted @ 2008-04-26 16:41  潮儿  阅读(582)  评论(0编辑  收藏  举报