对于应用程序来说,能够对NHibernate内部发生的事件做出响应式很有用的。这能够有助于实现一些类的功能或者扩展NHibernate的功能。

拦截器

IInterceptor接口提供了应用程序session的的回调方法,使得应用程序能够在持久化对象进行增删改查之前检测和/或者操作持久化对象的属性。一个应用场景是追踪审计信息。例如,下面的IInterceptor接口会在IAuditable实例新增的时候自动设置createTimeStamp,在IAuditable实例更新的时候自动更新lastUpdateTimestamp。

你可以直接实现IInterceptor或者(推荐)扩展EmptyInterceptor。

using

System; using NHibernate; using NHibernate.Type; public class AuditInterceptor : EmptyInterceptor { private int updates; private int creates; private int loads; public override void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types) { // do nothing } public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types) { if ( entity is IAuditable ) { updates++; for ( int i=; i < propertyNames.Length; i++ ) { if ( "lastUpdateTimestamp".Equals( propertyNames[i] ) ) { currentState[i] = new DateTime(); return true; } } } return false; } public override bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types) { if ( entity is IAuditable ) { loads++; } return false; } public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types) { if ( entity is IAuditable ) { creates++; for ( int i=; i<propertyNames.Length; i++ ) { if ( "createTimestamp".Equals( propertyNames[i] ) ) { state[i] = new DateTime(); return true; } } } return false; } public override void AfterTransactionCompletion(ITransaction tx) { if ( tx.WasCommitted ) { System.Console.WriteLine("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads); } updates=; creates=; loads=

;
} }

拦截器有两种类型:ISession-scoped 和ISessionFactory-scoped。

一个ISession-scoped 类型的拦截器会在使用ISessionFactory.OpenSession() 重载方法打开一个session时候被指定传入。

ISession session = sf.OpenSession( new AuditInterceptor() );

一个ISessionFactory-scoped 类型的拦截器会在产生ISessionFactory之前的Configuration 对象中设置。在这种情况下,配置后的拦截器会应用到所有通过ISessionFactory打开的session中,除非这个session在打开的时候显式设置了要使用的拦截器。ISessionFactory-scoped类型的拦截器必须是线程安全的,要注意不能保存特定session的状态,因为多个session会并发使用(潜在的)这个拦截器。

new Configuration().SetInterceptor( new AuditInterceptor() );

事件系统

如果你必须在你的持久化层中相应特定的事件,你可能还需要使用NHibernate 2 event 架构。事件系统可以作为拦截器的扩展或方案者替代品。

实际上所有ISession中所有的方法都对应一个事件,LoadEvent,  FlushEvent 等(查询XSD配置文件或者NHibernate.Event 名称空间来获得被定义的事件类型列表)。当一个请求由这些方法其中一个组成的时候,ISession产生一个相应的事件然后将它传到配置好的该类型的事件监听器中。这些待命的监听器就会执行和这些方法相同处理过程。然而,你也可以自己实现任意的监听器接口(例如,注册的ILoadEventListener接口实现将会处理 LoadEvent事件),在这种情况下他们的视线会用来处理ISession产生的所有load()方法请求。

监听器应该是单例,也就是说,它们被所有的请求共享,因此它们不能保存任何的状态信息。

自定义的监听器应该实现相应它要处理事件的接口和/或者扩展基类(或者甚至NHibernate已经实现的默认事件监听器,它们的实现为此而被定义成虚方法)。自定义的监听器可以编程式地通过Configuration 对象来注册,或者在NHibernate XML配置文件中指定。下面是一个自定义加载事件监听器的例子:

public class MyLoadListener : ILoadEventListener { // this is the single method defined by the LoadEventListener interface public void OnLoad(LoadEvent theEvent, LoadType loadType) { if ( !MySecurity.IsAuthorized( theEvent.EntityClassName, theEvent.EntityId ) ) { throw new MySecurityException("Unauthorized access"

);
}
}
}

你也需要配置入口来告诉NHibernate除了默认监听器之外还应该使用哪些监听器。

<hibernate-configuration> <session-factory>

        ...
        

<event type="load"> <listener class="MyLoadListener"/> <listener class="NHibernate.Event.Default.DefaultLoadEventListener"/> </event> </session-factory> </hibernate-configuration>

你也可以在程序中来指定:

Configuration cfg = new Configuration(); ILoadEventListener[] stack = new ILoadEventListener[] { new MyLoadListener(), new DefaultLoadEventListener() }; cfg.EventListeners.LoadEventListeners = stack;

声明式地指定的监听器不能够共享实例。如果相同的类名在多个<listener/>标签中使用,每个引用都会导致一个独立的该类的实例。如果你需要在两个监听器类型之间共享监听器实例,你不惜使用这种编程式的注册方式。

为什么要在配置的时候实现一个借口和指定特定的类型呢?嗯,一个监听器的实现可以时间多个事件监听接口。在注册的时候额外地定义这些类是为了能够在配置的时候灵活的关闭或打开这些自定义的监听器。

NHibernate官方文档中文版--拦截器和事件(Interceptors and events)的更多相关文章

  1. NHibernate官方文档中文版——批量插入(Batch inserts)

    A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this: 一 ...

  2. NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)

    映射声明 对象/关系映射在XML文件中配置.mapping文件这样设计是为了使它可读性强并且可修改.mapping语言是以对象为中心,意味着mapping是围绕着持久化类声明来建立的,而不是围绕数据表 ...

  3. NHibernate官方文档中文版——事务和并发(Transactions And Concurrency)

    NHibernate本身并不是一个数据库.它是一个轻量级的对象-关系映射工具.因此,它的事务管理代理给对应的数据库连接.如果这个连接代理了一个分布式的事务,ISession管理的操作就会自动成为整个分 ...

  4. NHibernate官方文档中文版-框架架构(Architecture)

    总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ...

  5. NHibernate官方文档中文版--ISessionFactory的配置(ISessionFactory Configuration)

    由于NHibernate是被设计应用在许多不同环境中的,因此它存在很多配置参数.幸运的是,这些参数大多都有合理的默认值,而且NHibernate发布的时候伴随着一个App.config 例子(可在sr ...

  6. NHibernate官方文档中文版--只读实体类型(Read-only entities)

    重点 NHIbernate处理只读对象的方式可能和你在别处看到的不同.不正确的使用方式可能造成不可预料的结果. 当一个实体是只读的时候: NHIbernate不会对实体的简单属性和单向关联数据检查数据 ...

  7. NHibernate官方文档中文版——持久化类(Persistent Classes)

    持久化类是一个应用程序中的类,主要用来实现业务逻辑(例如,在电商应用中的客户和订单类).持久化类,就像它的名字一样,生命周期短暂并且用来持久化的据库对象实例. 如果这些类的构造能够依照一些简单的原则, ...

  8. TestNG官方文档中文版(2)-annotation(转)

    1. 介绍    TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整个系统,例如运用服务器). 编写一个测试的 ...

  9. bootbox.js官方文档中文版

    bootbox.js官方文档中文版简介:Bootbox.js是一个小型的JavaScript库,基于Bootstrap模态框开发,用于创建可编程的对话框. 不像原生的alert等对话框,所有的Boot ...

随机推荐

  1. 神秘的subsys_initcall【转】

    转自:http://blog.chinaunix.net/uid-12567959-id-161015.html 在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢? ...

  2. ARM linux的启动部分源代码简略分析【转】

    转自:http://www.cnblogs.com/armlinux/archive/2011/11/07/2396784.html ARM linux的启动部分源代码简略分析 以友善之臂的mini2 ...

  3. C11 标准特性研究

    前言 - 需要点开头 C11标准是C语言标准的第三版(2011年由ISO/IEC发布),前一个标准版本是C99标准. 相比C99,C11有哪些变化呢!!所有的测试全部基于能够和标准贴合的特性平台. 但 ...

  4. 前言-关于学习OC还是学习Swift的个人理解

    一直在考虑一个问题!到底是学swift好呢还是学OC好. 然后得到了解答: 1.如果你只是对苹果系统软件开发有兴趣,把开发作为一种业务爱好,那么选swift就没错,swift也是大势所趋. 2.如果你 ...

  5. printf格式化输出

    基本格式 printf [format] [文本1] [文本2] .. 常用格式替换符 %s 字符串 %f 浮点格式 %c ASCII字符,即显示对应参数的第一个字符 %d,%i 十进制整数 %o 八 ...

  6. hdu 1671(字典树判断前缀)

    Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. QT中ui更改后不能更新的解决方法

    ui源文件到界面显示的原理可以网上搜索,这里不再描述.简单讲就是先要从*.ui生成ui_*.h然后再编译,所以界面未更新实际上是因为ui_*.h这个文件没有更新导致的. 出现此问题后我尝试了以下几个方 ...

  8. 【转载】关于Python的Mixin模式

    本博按: mixin是看起来是多继承的一种,但是,这种继承并不作为父类存在,而是增加功能到子类中. 像C或C++这类语言都支持多重继承,一个子类可以有多个父类,这样的设计常被人诟病.因为继承应该是个” ...

  9. PHP策略设计模式

    <?php /** 抽象策略角色,以接口实现 */ interface Strategy { /** 算法接口 */ public function algorithmInterface(); ...

  10. SSH Secure File Transfer上传文件错误:encountered 1 errors during the transfer解决办法

    在使用SSH 工具向Linux服务器上传文件时,弹出 encountered 1 errors during the transfer 错误. 解决方案: 1.准备上传的那个文件所在目录路径存在(), ...