Step 1 Nhibernate 学会简单使用

来源:互联网 发布:软件测试培训机构 编辑:程序博客网 时间:2024/04/20 11:54

对于DataSet的编码直接破坏了透明性。他很明显知道在你代码里面是用的存储机制,他直接影响你编码的方式。另一种存储途径是使用ORM工具。Microsoft正在开发这样一个框架(ObjectSpaces),但是最近宣布他将推迟到2006年。NHibernate,一种OpenSource的解决方案,已经存在并且可以用来解决同样的一系列问题。使用NHibernate,你的代码和你的数据库结构可以(),在OR层唯一可见的实物就是映射文件。通过NHibernate,你将看到:这个OR框架是由一系列配置文件组成(连接到数据库,标识数据方言)以及将你的领域对象映射到数据表。


现在有很多的ORM框架,包含一些商业的和一些开源的。本文的目的是关注NHibernate这个ORM。他有很多的来自Java世界的驱动,以及他非常容易上手。但是,如果你对本文讲的大体的技术有兴趣,我建议看一下其他更合适呢需求的存在选择。


第一,你要从http://www.nhibernate.sourceforge.net/下载这个框架。在你的程序集里面引用它。下一步在你的程序配置里面增加NHibernate配置,告诉他你要存储的东西。本文使用MSSQL,虽然你可以很简单的转换到Oracle,MySQL或者其他的数据库。为了映射SQL Server实例,你的配置如下:

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>


<nhibernate>

<add key="hibernate.show_sql" value="true" />

<add key="hibernate.connection.provider"

value="NHibernate.Connection.DriverConnectionProvider" />

<add key="hibernate.dialect"

value="NHibernate.Dialect.MsSql2000Dialect" />

<add key="hibernate.connection.driver_class"

value="NHibernate.Driver.SqlClientDriver" />

<add key="hibernate.connection.connection_string"

value="data source=(local);database=MySchool;user id=sa;password=1980;connection reset=false;connection lifetime=5; min pool size=1; max pool size=50" />

nhibernate>

configuration>

 

一旦你配置好这个框架来识别你数据的存储,下一步就是建立你的领域模型和数据库表现。没有一个固定的顺序,如果你的程序建立在数据库结构已经建立好的基础上,从这开始是合适的。否则,如果数据库就是一个存储对象的地方,那么从领域模型开始可能更有意义。还有第三种选择,从映射文件开始,映射文件描述了类与数据库表之间的关系。现在NHibernate提供了一个工具它可以从映射文件中自动生成DDL。这个项目最近增加了对NAnt任务的支持,他将通过映射文件自动生成C#代码文件。综上所述,你可以通过就建立映射文件这个实现基础,来使用NHibernate工具作剩下的事情。


领域模型

我们将从领域模型开始。在这篇文章里面,我们关注一个企业级程序里面的一小部分。明确的说,我们将从大学的注册系统开始。为了这个目的,我们设计下面几个类:

1. Department:描述大学的系

2. UniversityClass:学校的一个班级

3. Professor:学校的教授

4. Student:学生

每一个类有他自己的数据字段,但是他们之间的关系如下:


Department可以有 0,1,或者更多的Professor。一个Professor可以教很多个Department。一个Department包含了大于等于1个Class。一个Class只属于一个Department。一个Class只能被一个Professor交,但是一个Professor可以教几个Class。一个Class包含很多学生。在Department与Student之间没有什么直接的关系。


我们的领域对象非常简单。下面是类与数据字段:


当然,你可以提供Public属性来包装这些字段,那是一种好的编程习惯。虽然NHibernate可以通过Private,Protected字段来工作,通过属性来访问字段更加有意义。


第二,记住Professor和Student共享一个表。在领域模型里面,他们共享几个数据字段。在我们的领域模型里面,通过继承来表现这个关系。在这个方案里面,他们实现一个Person接口来表现。


最后,你将看到我们的集合字段是使用IDictionary来定义的。当你在你的领域里面定义你的集合,紧贴这个系统提供的接口。这通常是一个好的实践,他给予NHibernate最大的宽松。

数据库:


现在让我们看一下数据库。第一个表是Department,只是简单的存储ID和名字。下一步,我们将为Student与Professor建立表。但是,如果你仔细看,Professor与Student几乎是差不多的(显而易见,他们都属于人类)。他们有First与Last name,和一些字符串标志(Professor的Title,学生的SNN)。替代著2个表,我们建立一个表叫Person。他对于每一个人将有一个唯一的ID,他们的Fisrt Last Name,一个标志字段,一个叫PersonType的字段(我们用来区别Student与Professor),最后,我们需要一个班级表。他有一个唯一的ID,关于班级所有的描述信息,&2个外键,PersonID(与教这个班级的Professor关联),DeptID(这个班级属于哪一个Department)。

 

其他2个表是联合标,用于构建Student与Class,Department与Professor之间的many-to-many的关系。这2个表简单的匹配合适的原表ID,形成一个联合。


映射文件


下一步是提供映射文件用来从数据表来填充我们的领域对象。每一个类多需要自己的映射文件,可以存储你喜欢的东西。我们保持我的方式(与类文件结合以至于简单的操作当我改变模型的时候)。不管怎样,在你的程序里面每一个持久类作一个映射。


映射文件关联你的类与数据库里面的持久属性。你的类可以有非之久化属性。这是关于透明数据库层的一种很好的方式。如果你的领域对象调用运行时计算属性,你的类可以与持久化对象混合。你的映射文件可以忽略非持久化属性。


让我们开始为Department建立映射。所有的映射文件是XML文件。他们开始于xml version="1.0" encoding="utf-8" ?>

下一步生命这个文件是NHibernate的映射文件。NHibernate的根部元素象这样:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

hibernate-mapping>
 

这是样板文件,现在让我们开始建立真实的映射内容。第一我们需要告诉NHibernate哪一个类被映射(使用标签)。当我们要给NHibernate类型时,我们需要给全名。对于Department来书全名就是“TestNH.DomainObjects. Department”,程序集是“TestNH”。我们需要为类填充表明。在这个方案里面department

<class name="TestNH.DomainObjects.Department,TestNH" table="department">

class>
 

我们做的很好。剩下的就是将持久化字段映射到数据库结构。所有的属性映射共享一个共同的特征:类上面属性,数据库表结构里面的列,以及要持久还字段类型。不管怎样的属性,上面三项多会出现。


让我们看一下标准属性:Department的Name属性。这个属性声明为string,数据库里面定义NVarchar(50).这个属性非常直接。

<property name="Name" column="deptname" type="string(50)">property>
 

所有类的标准属性跟这个差不多。注意:跟在类型后面的长度不在需要,现在NHibernate不赞成,将反射处理配置。事实上,最新的版本,你可以同type属性一起删除。NHibernate将会检查映射属性的类型。


一个比较有趣的是Department的ID字段。每一个类有一个字段包含数据唯一标识。对于♂的模型,每一个类多有ID属性(为了这种目的)。你必须提供标准的属性集,以及2个注意的地方(generator,unsaved-value)。


ID字段的Generator是让NHbernate知道,唯一标志符怎么建立:由程序员,由NHibernate,或者数据库本身。不同的程序有不同的主键生成方式,不同的数据库为管理这些值提供了不同唯一的服务,以至于你必须基于你的需求与你的构架小心的挑选。Generator有下面这些值:

l Identity:数据库标志类型,MSSQL2000,MySQL 等等

l Sequence:唯一值(DB2,Oracle)

l Hilo:使用Hi/lo算法来生成标志符的值

l Native:自由选择


我们将使用native。Unsaved-value属性是为Id属性指定一个默认值当这个对象还没有持久化的时候。在这个方案里面,既然♂让ID属性的创建由数据库管理,使用默认值是非常有用的。

<id name="ID" column="ID" type="Int32" unsaved-value="null">

<generator class="native">generator>

id>
 

到现在我们看看配置文件

xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

<class name="TestNH.DomainObjects.Department,TestNH" table="department">

<id name="ID" column="ID" type="Int32" unsaved-value="null">

<generator class="native">generator>

id>

<property name="Name" column="deptname" type="string(50)">property>

class>

hibernate-mapping>
 


如果我们就这样,我们通过映射文件从数据库里面装载东西,♂可以得到Department列表(包含ID,Name值),但是Classes与Professors将是null。,因为♂没有在映射文件里面映射。如果一个属性不被映射,他将被NHibernate忽略。


下面,我们来处理Collection属性(他们得特殊的需求)。让我们看一看类。一个UniversityClass实例列表。记住我们这个模型的需求:一个department包含多个UniversityClass,但是一个UniversityClass只属于一个department。这是one-to-many的关系。对于这个模型,♂使用(或者)来映射一个集合,不是一个单一实例。

<bag name="Classes">

<key column="DeptID">key>

<one-to-many class="TestNH.DomainObjects.UniversityClass,TestNH"/>

bag>
 

Bag对应的IList,而Set对应的是Set


NHibernate 进阶

作者:Justin Gehtland


(原文:请点击这里)
    在我的最近文章中,我介绍了 Nhibernate。在这里和在其他的论坛中 , 因为我没有强调NHibernate 只是许多可得的 ORM 解决方案之一,(事实上,现在对.NET开发者来说,开源的加上商业的 ORM 的架构现在是超过 50个可供选择)。 作为一个开发顾问,我会经常用到Hibernate(大家都知道它吧)既然我必须在.NET平台下选择一个,NHibernate是我最明智的选择。 我想在这里脱离.NET平台来研究一下这个框架,并谈谈我们能从它获得的益处。

我的上一篇文章中介始示范了应用Nhibernate建一个简单应用(大学注册登记)的起步示例。下面我将介绍更多使用Nhibernate的技术,这次我们的目标给你一些在对特别大数据量查询的高吞吐量、高并发性的应用需求下使用Nhibernate的方式。

为了达到这个目标,我将分成下面四部分来讲:最佳的Session管理方式,指导使用HQL查询数据库,怎样延迟载入对象集合及对象生存周期管理。

 

第一部分:会话管理

在我的前一篇文章中,我实现了一个非常简单的为管理SessionFactory和Sessionr的名为RegMgr的类:它在其构造函数中根据配置创建了一个SessionFactory,然后在每一个方法中使用SessionFactory创建Session,使用这种方式有几个问题。

首先, 每个RegMgr 对象都需要建造一个新的 SessionFactory, 这将耗费非常昂贵资源。 每个SessionFactory都意味对你的应用中的实体与相应的数据库进行一次建模。其实仅仅在你应用需要多个数据库的支持才需创建多个SessionFactory的实例,而我的简单例子不是,所以无需这样。

    第二,每个方法从这个Factory创建了一个新的Session。这种方式每当方法完成都会关闭Session并释放锁定的数据库,从而提供了最大程度的并发保护机制。然后这也结束这个会话所有关联对象的状态,其实Session创建也比较耗费资源的,虽然不像SessionFactory那样。

第一个问题的答案是可以肯定的,那就是确认你只创建 SessionFactory 一次。 RegMgr 原来是这样的:

public class RegMgr : DBMgr
{
        Configuration config;
        ISessionFactory factory;
              
        public RegMgr()
        {
               try
               {
                       config = new Configuration();
                       config.AddClass(typeof(nhRegistration.Department));
                       config.AddClass(typeof(nhRegistration.Person));
                       config.AddClass(typeof(
                               nhRegistration.UniversityClass));
                       factory = config.BuildSessionFactory();
               }
               catch (Exception ex)
               {
                       // handle exception
               }
        }
        // etc...
}
应修改如下:

public class RegMgr : DBMgr
{
        static Configuration config;
        static ISessionFactory factory;
 
        static RegMgr()
        {
               try
               {
                       config = new Configuration();
                       config.AddClass(typeof(nhRegistration.Department));
                       config.AddClass(typeof(nhRegistration.Person));
                       config.AddClass(typeof(
                               nhRegistration.UniversityClass));
                       factory = config.BuildSessionFactory();
               }
               catch (Exception ex)
               {
                       // handle exception
               }
        }
        // etc...
}
这样,所有RegMgr的实例所共享了这同一个SessionFactory,这就节省大量资源。

    

     看起来用同样的方式来解决Session管理的问题也会一样好,那为什么不将一个Static的Session加入到这个类中并仅仅在那个SessionFactory中创建并打开它呢,然后所有的方法都使用同一个Session。答案有两个:首先,共享的Static的Session被多个线程同时访问时可能是线程不安全的,各个事物(Transiction)会相互干扰的;其次,它也大部分时处在空闲状态,但是还是保持一物理数据库连接。而数据库连接是非常珍贵的资源。每一种数据访问方式都有一个相同的目标就是使服务端的游标与一个客户端的连接维持在最短的时间内,Nhibernate也同样如此。因此,无所事事开着的Session相反会是一个很费资源的方式。

     替代的解决方案是使用一个非连接态的Session对象:为你所有调用的函数创建一个共享的Session实例或静态对象,在其每个函数的调用开始打开它,离开函数总是关闭它。代码可能是这样的:

public IList getClasses()
{
        IList classes = null;
        try
        {
               // session is declared in instance scope
               session.Reconnect();
               ITransaction tx = session.BeginTransaction();
               classes = session.CreateCriteria(
                       typeof(UniversityClass)).List();
              
        }
        catch (Exception ex)
        {
               // handle exception
        }
        finally
        {
               session.Flush();
               session.Disconnect();
}
        return classes;
}
    这样你总能重用同一个Session对象,这样不同方法因调用Session所花费的资源会减到最少,而数据库的资源也都会因及时释放也会使它们协同工作得很好。

 

第二部分:HQL

我们有时需要NHibernate来处理如:“查询所有部门”或“查询某个学生”之类更特殊更复杂的需求。具体应用中可能需要提供复杂的搜索与数据过滤操作来执行数据查询。NHibernate 提供了与SQL很相似的HQL(the Hibernate Query Language) 。 在 HQL 和 SQL 之间的最大不同点在FROM子句:在HQL中可以使用一个或多个类来表示SQL中的一个或多个表名。既然 NHibernate 的目标就是用Domain objects来提供一个透时的数据层,既然Domain objects与数据表具有对应关系,那么就不再需要提供表名给Nhibernate了。

举例来说,在我的“University registration”程序中,我们可能想知道那些班已安排好但还没有分配任课教师。知道哪一班级已经被预定但是尚未被分配Professors会更好。( 顺便我们可能需要知道其中那些是一年级的班级)。我们为得到它们可以在RegMgr中添加这样一个方法:

public IList getClassesNoProf(){}
然后使用NHibernate来进行完整的实现:

IList classes = this.getClasses();
IList results = new ArrayList();
foreach(UniversityClass c in classes)
{
        if(c.Prof == null) results.Add(c);
}
return results;
     这里我从数据库获取所有的班级然后遍历它们,并获得最终符合条件的班级。 这样可能会很慢,因为获取了所有对象而最后能需要其中一些甚至很少的一部分,数据表越大这种方式会越慢而难以接受。

     所以我们要做的是数据库中直接过滤,这可使数据在我们程序之间的网络带宽需求降至最低(因为数据库通常在网络中的其它服务器上)。

public IList getClassesNoProf()
{
        IList results = null;
        try
        {
               ISession session = factory.OpenSession();
               results = session.Find(
                       "from nhRegistration.UniversityClass as
                       uc where personid is null");
        }
        catch (Exception ex)
        {
               // handle exception
        }
        return results;
实现一个 HQL 查询主要是通过调用 ISession.Find() 方法。 使用它可以执行任意一个查询。 HQL 支持几乎所有SQL子句, 如排序和分组(order by,group by)。为了得到相同的而按Name属性排序的UniversityClass对象集合只需对这个查询做这样的改变就以了:

results = session.Find("from nhRegistration.UniversityClass as
uc where personid is null order by uc.Name asc");
特别注意: 审查排序子句的语法。这里我们按Name来排序,如果你参考我上一篇文章中的映射文件中就有一个名为 “classname”的列。当书写Order子句时,既可以使用属性名也可以数据表的列名,但是如果选择属性你就不得不使用类的别名作为前缀(这个例中就是uc),而使用列名时则不需要(“order by classname asc”)。我宁愿使用类别名加上属性我的方式,因为使我的代码与数据库相分离。

这个HQL查询缺少普通SQL中的SELECT子句,这实际暗示地告诉NHibernate 返回所有From中出现的类型的所有实例。 有时我们并不需要整个对象,比如我们可能仅需要显示课程的名称而无需知道其教师是谁,这时如果载入并初始化这些实例就有些过了,为了克服这个缺点,就可以加入SELECT子句来表示你需要的属性,这样你将得到一个仅包含那些属性的Ilist。在我们的示例中是这样的:

public IList getClassNamesNoProf()
{
        IList results = null;
        try
        {
               ISession session = factory.OpenSession();
               results = session.Find("select uc.Name from
                       nhRegistration.UniversityClass as uc
                       where personid is null order by uc.Name asc");
        }
        catch (Exception ex)
        {
               string s = ex.Message;
        }
        return results;
}
同时,我们也能仅仅得到没有老师的班级数量。

results = session.Find("select count(uc.Name) from
nhRegistration.UniversityClass as uc where personid is null");
     正如你所看到的, HQL在大部分地方与SQL相似,除了用面象对象描述来替换数据元素。对于大多数正常的对象持久化工作你完全可以不理会HQL,但是为使更多以数据为中心的工作能完成得更快,善于HQL就会事半功倍。

         第三部分:延迟载入(Lazy Loading)

     NHibernate一个最棒的地方就是完透明地载入父类的相应子类。你仅仅要求得到父类的时候,而 NHibernate 会去载入所有的子类无论是这种一对一还是一对多的关系。如果这是唯一的选项,那这也是Nhibernate最坏的事情。

    这种缺省行为的问题是你的代码对于数据库的使用完全透明而在代码运行时一点也不透明。我的意思因为所有关系被装载对于任何大小的树对象模型来说可能是非常慢的。

    现在就以“University registration”的 Domain model为例:这里仅有四个类,但当载入单个Department对象时,就会同时载入一个UniversityClass的集合、Processor的集合。而每一个UniversityClass也会载入一个Processor对象和包括很多Student对象的集合。如果数据库的里有足够多的数据, 仅仅载入一个Department对象已是很笨重了。现在想象一个RegMgr.getAllDepartments()方法,问题就很明显了。

     解决这个问题的方法是延迟集合对象的载入。要声明一个要延迟载入一个对象集合很简单,只需要在映射文件中相应元素添加一个特性:lazy=”true” 。 举例来说, 要使我们Deparment延迟载入集合,原来的映射文件是这样的:

<set name="Classes" cascade="all">
        <key column="deptid"/>
        <one-to-many class="nhRegistration.UniversityClass,
               nhRegistration"/>
</set>
现在只需做如下修改就可以了:

<set name="Classes" cascade="all" lazy="true">
        <key column="deptid"/>
        <one-to-many class="nhRegistration.UniversityClass,
               nhRegistration"/>
</set>
延迟载入的意思就是直到需要载入集合中的元素才将它们载入。这样你延迟了加载了时间,同时如果当你的执行代码从来不使用它们的时候这些集合对象根本就不会被载入。比如执行的代码可能需要访问一个具有一个或多个Processor的Department,而对于那些不符合条件的Department,就可能从不需要载入它的UniversityClass集合, 这就节省了许多时间( 无论是客户端应用还是数据库)。

     但是这有一个缺点就是延迟载入需要最初装载父对象的Session来载入。要是你的代码象我的大学注册应用一样,即将所有的数据管理都放进了一个单一的数据管理类,这样你才能在在这人数据管理类中看到延迟载入好处。让我们再看一下RegMgr.getDepartments():

public IList getDepartments()
               {
        IList depts = null;
        try
        {
               ISession session = factory.OpenSession();
               ITransaction tx = session.BeginTransaction();
               depts = session.CreateCriteria(typeof(Department)).List();
                       session.Close();
        }
        catch (Exception ex)
        {
               // handle exceptions
        }
        return depts;
}
 

对有力的技术缺点是,被延期的负荷需要最初的会议装载父母物体用来装载懒惰的收集。 如果你的密码跟随我们已经为大学登记申请用的式样,即分开所有的数据管理进一个单一数据经理班级,然后你才能在那一个数据经理班级中见到懒惰载入的利益。再一次看 RegMgr.getDepartments():

    这里我们载入所有部门后产刻关闭了Session。当类的相关集合标记为延迟载入时,如果你尝试在业务代码中访问相关集合,这里你会获得一个“LazyInitializationException”的异常:这就意味着你既不能访问集合中的某个成员也不能获取集合中相关的合计数据如成员总数,因为它根本不存在。并且因为Session已经关闭,它将再也不会将工作,除非你将这个集合对象的父对象关联到另外一个Session。

    所以,你可以选择将任何需要有益于延迟载入业务逻辑代码移入到数据管理类中,或者选择直到从这个方法返回之前都不关闭Session。我建议,除非你对这个实现费了很长时间或者有足够多的异常处理代码,否则你不要选择后者。

 

第四部分:拦截机制与持久对象生存周期(Interceptors and Persistent Lifecycle)

    持久化对象在其生存周期中有四个主要时刻:即被装载,更新,保存和删除四个时刻( 记住, 保存是指一个新对象第一次被持久化,而更新发生在提交改时的对象时。), 更新发生当你委托对一个现有的物体变化)。 在我们已有代码中, 你能在这些时候做些事情的唯一方法是在数据管理类中相应方法中来加点你需要的代码(如getDepartment() 或 saveStudent())。但问题是,它们仅仅在数据管理类中,而如果它们是持久化对象总是需要的一部分, 这样做你就可能就将持久化对象与你的数据管理类大过紧密地联系在一起了。

如果持久化对象可以自己处理这些事刻这样会清晰。NHibernate 提供一个接口使Nhibernate在相应生存周期的时刻通知类的实例。这个接口是 ILifecycle,它是这样被定义的:

      public NHibernate.LifecycleVeto OnUpdate(ISession s){}
      public void OnLoad(ISession s, object id){}
      public NHibernate.LifecycleVeto OnSave(ISession s){}
      public NHibernate.LifecycleVeto OnDelete(ISession s){}
四个方法中有三个都会返返回一个LifecycleVeto,来决定对象下一步的生命周期事件处理。这样你就可以在保存对象之前,检查对象状态来决定更新或删作它,并且如果这些状态不符要求的条件,也可以取消对象的保存。如果取消了也就意味对象的其它操作也会失败,也就是对象不会被保存、更新或删除。

四个方法中的三个给你的物体一个机会藉由归还 LifecycleVeto 更进一步停止给定的生命周期事件的处理。使用这一个机制,你能在~之前解救质问物体的内在状态,更新或划除它,而且如果那州不符合你的申请一些标准,你能否决事件的完成。 归还否决权导致事件的其它部分默默地失败, 这意谓,物体没有在解救, 更新或划除,但是没有那一种事实的通知是申请的可得其他地方。 相反将在这些引用它们的方法中产生一个异常。

这三个方法最初是为了提供程序员自己来处理相互依赖对象之间相关系来替代Nhibernate处理的一种可选方式。 (你能更大范围对层级关联对象进行控制)但是你不应该使用Onload方法去做它,虽然你能够象NHibernate缺省行为一样。

    拦截是类实现了IInterceptor 接口。这些类实现了相同类型的生存周期方法 (其它一些生存周期方法) ,但是这些在类中被定义的方法会在Session中任一一个对象的生存周期事件发生时被调用。并且在这个拦截接口中你也不能否决事件继续运行,但是你能修改对象并返回一个表明是否你做过修改的布尔值。加上在Iinterceptor中发生的事件是很多的:

public int[] FindDirty(object entity, object id,
        object[] currentState, object[] previousState, string[]      propertyNames, NHibernate.Type.IType[] types){}
public object Instantiate(Type type, object id){}
public bool OnFlushDirty(object entity, object id, object[]
        currentState, object[] previousState, string[] propertyNames,
        NHibernate.Type.IType[] types){}
public object IsUnsaved(object entity){}
public bool OnLoad(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public bool OnSave(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public void OnDelete(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public void PreFlush(System.Collections.ICollection entities){}
public void PostFlush(System.Collections.ICollection entities){}
    在“University Registration”这个示例中,我想要实现一个一致的统一的日志机制。为了做那,我创建了一个LoggingInterceptor 的类, 它将在任何对象载入与持久化时写一个消息至日志(其他的没用方法则不记录)。

public bool OnLoad(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types)
{      
        string msg = string.Format("Instance of {0}, ID: {1} loaded.",
entity.GetType().Name, id);
        log(msg);
        return false;
}
 
public bool OnSave(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types)
{
        string msg = string.Format("Instance of {0}, ID: {1} saved.",
entity.GetType().Name, id);
        log(msg);
        return false;
}
 
private void log(string msg)
{
        // app-specific logging behavior
}
最后就要要在创建Session的时候载入一个这个Interceptor的实例以便能拦截所有对对象的相关操作。

ISession session = factory.OpenSession(new LoggingInterceptor());
这样所有的被这个Session载入的domain object的载入与保存操作都会被拦截记录下来日志。

 

结语:

正如你所见到的,Nhibernate有比一些映射文件和一个叫Session.Find()的更多东西,它有非常大的可扩展性。 对于小而简单的应用来说,你能使用Nhibernate来处理复杂和很多的数据访问代码,不必更多考虑我在这里谈到的各种特征。如果应用需求越来越大,越来越复杂,这里谈到将很会有用,因为你知道Nhibernate 几乎可以定制任何你想怎样进行对象持久化的特定方式。我们已经差不多对它有了一个大致的了解。

 
原创粉丝点击