NHibernate IPostInsertEventListener:多次执行插入

时间:2013-05-06 09:40:55

标签: events nhibernate testing triggers fluent-nhibernate

我正在尝试测试一个简单的基于NHibernate的审计机制,该机制将每个已更改属性的一行存储到changelog表中。它实际上做的是按预期执行实际的insert语句并执行两次审计日志记录。

所以,这就是我的工作:

string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=audittest;Integrated Security=SSPI;";
FluentConfiguration config = Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
                                                        .ConnectionString(c => c.Is(connectionString)).ShowSql())
                                                        .Mappings(x => x.FluentMappings.Add<Class1ClassMap>())
                                                        .Mappings(x => x.FluentMappings.Add<ChangeLogMap>())
                                                        .ExposeConfiguration(cfg =>
                                                        {
                                                            NHibernateAuditListener listener = new NHibernateAuditListener();
                                                            cfg.AppendListeners(ListenerType.PostInsert, new[] { listener });
                                                        });
ISessionFactory sf =  config.BuildSessionFactory();
ISession session = sf.OpenSession();
using (ITransaction tr = session.BeginTransaction())
{
    session.Save(new Class1()
        {
            FirstName="Peter",
            LastName="Pan",
            Id=100

        });
    tr.Commit();
}

修改

将日志记录代码更改为简单的内容以查看失败:

public void OnPostInsert(PostInsertEvent @event)
{
    if (@event.Entity is IAuditable)
    {                
        Console.WriteLine("----write audit----");
        for (int index = 0; index < @event.State.Length; index++)
            Console.WriteLine("----store changes of property {0}----",
                              @event.Persister.PropertyNames[index]);
    }
}

这会生成以下输出:

NHibernate: INSERT INTO "Class1" (FirstName, LastName, Id) VALUES (@p0, @p1, @p2); @p0 = 'Peter' [Type: String (0)], @p1 = 'Pan' [Type: String (0)], @p2 = 1 [Type: Int64 (0)]
----write audit----
----store changes of property FirstName----
----store changes of property LastName----
----write audit----
----store changes of property FirstName----
----store changes of property LastName----

如您所见,不是EventHandler代码是错误的,而是调用它的框架意外行为(调用OnPostInsert方法两次)。任何想法为什么会发生这种情况?

SAMPLE PROJECT DOWNLOAD

1 个答案:

答案 0 :(得分:2)

好的每个人,问题都存在于程序内的处理细节中。您正在构建一个FluentConfiguration实例,它可以动态创建基本的NHibernate配置。

这是在调用这两行时完成的(变量配置的类型为FluentConfiguration):

new SchemaExport(config.BuildConfiguration()).Create(true, true);

ISessionFactory sf = config.BuildSessionFactory(); 

FluentConfiguration缓存第一个创建的实例,并重用它来为ISessionFactory - 实例创建新实例。在两次调用中,调用ExposeConfiguration实例的FluentConfiguration。因此,会话中有{2}个实例持久保存数据。

试试这样:

NHibernateAuditListener

string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=audittest;Integrated Security=SSPI;"; var config = Fluently.Configure().Database(MsSqlConfiguration.MsSql2008 .ConnectionString(c => c.Is(connectionString)).ShowSql()) .Mappings(x => x.FluentMappings.Add<Class1ClassMap>()) .Mappings(x => x.FluentMappings.Add<ChangeLogMap>()) .ExposeConfiguration(cfg => { NHibernateAuditListener listener = new NHibernateAuditListener(); cfg.AppendListeners(ListenerType.PostInsert, new[] { listener }); }) .BuildConfiguration(); new SchemaExport(config).Create(true, true); Console.WriteLine("----------------------------------------------"); ISessionFactory sf = config.BuildSessionFactory(); ISession session = sf.OpenSession(); using (ITransaction tr = session.BeginTransaction()) { session.Save(new Class1() { FirstName="Peter", LastName="Pan", Id=100 }); tr.Commit(); } 内你现在拥有真正的NHibernate配置实例,只注册了一个Listener。

知道了吗?!