NHibernate,连接的子类层次结构,仅在PreUpdate事件中修改的实体上的PreUpdate事件数据更改不会保留

时间:2011-03-31 15:58:49

标签: nhibernate

概述:使用NHibernate,我正在尝试使用连接的子类进行3层次的层次结构。有一个Category,它继承自AuditableEntity(用于添加PreUpdate和PreInsert审计跟踪),最终从实体继承。

问题:没有任何对AuditableEntity对象的数据更改,这些更改与Ayende的博客文章完全相同,都会持久保存到数据库中。 PreUpdate代码成功更新了AuditableEntity对象属性,但就好像NHibernate没有看到AuditableEntity那样脏,因为没有更新sql语句。

Hbm

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Learning"
                   namespace="Learning.entities">
  <class name="Entity" >
    <id name="Id" type="guid">
      <generator class="guid.comb"></generator>
    </id>
    <version name="Version"/>

    <joined-subclass name="AuditableEntity" >
      <key column="AuditableEntity_id"></key>

      <property name="CreatedOn" ></property>
      <property name="CreatedBy" ></property>
      <property name="LastModifiedOn" ></property>
      <property name="LastModifiedBy" ></property>

      <joined-subclass name="Category">
        <key column="AuditableEntity_id"></key>
        <property name="Name" />
      </joined-subclass>

    </joined-subclass>    
  </class>
</hibernate-mapping>

听众的NHibernate配置

<event type="pre-insert">
  <listener class="Learning.eventlisteners.AuditInsertEventListener, Learning" />
</event>
<event type="pre-update">
  <listener class="Learning.eventlisteners.AuditUpdateEventListener, Learning" />
</event>

预先更新代码

namespace Learning.eventlisteners
{
    public class AuditInsertEventListener : IPreInsertEventListener
    {
        public bool OnPreInsert(PreInsertEvent @event)
        {
            var audit = @event.Entity as IAuditable;
            if (audit == null)
                return false;

            var createdOn = DateTime.Now;
            var createdBy = loggedOnProfile;

            AuditCommon.Set(@event.Persister, @event.State, "CreatedOn", createdOn);
            AuditCommon.Set(@event.Persister, @event.State, "CreatedBy", createdBy);
            AuditCommon.Set(@event.Persister, @event.State, "LastModifiedOn", createdOn);
            AuditCommon.Set(@event.Persister, @event.State, "LastModifiedBy", createdBy);

            audit.CreatedOn = createdOn;
            audit.CreatedBy = createdBy;
            audit.LastModifiedOn = createdOn;
            audit.LastModifiedBy = createdBy;

            return false;
        }
    }

    public static class AuditCommon
    {
        internal static void Set(IEntityPersister persister, IList<object> state, string propertyName, object value)
        {
            var index = Array.IndexOf(persister.PropertyNames, propertyName);
            if (index == -1)
                return;
            state[index] = value;
        }
    }

    public class AuditUpdateEventListener : IPreUpdateEventListener
    {
        public bool OnPreUpdate(PreUpdateEvent @event)
        {
            var audit = @event.Entity as IAuditable;
            if (audit == null)
                return false;

            var lastModifiedOn = DateTime.Now.AddSeconds(28);
            var lastModifiedBy = loggedOnProfile;

            AuditCommon.Set(@event.Persister, @event.State, "LastModifiedOn", lastModifiedOn);
            AuditCommon.Set(@event.Persister, @event.State, "LastModifiedBy", lastModifiedBy);

            audit.LastModifiedOn = lastModifiedOn;
            audit.LastModifiedBy = lastModifiedBy;

            return false;
        }
    }
}

代码

using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
    var category = session.Query<Category>().First();
    category.Name = "Updated";
    session.SaveOrUpdate(category);
    transaction.Commit();
}

观察:如果我在调用SaveOrUpdate之前手动更新其中一个AuditableEntity属性,则显然会触发PreUpdate事件并进行适当的数据更改,然后将AuditableEntity数据持久保存到数据库

using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
    var category = session.Query<Category>().First();
    category.Name = "Updated";
    category.CreatedOn = DateTime.Now;
    session.SaveOrUpdate(category);
    transaction.Commit();
}

帮助:我显然不想虚拟编辑AuditableEntity属性,所以我在这里做错了什么想法?

1 个答案:

答案 0 :(得分:0)

为了回答这个问题,我撰写了一篇nhibernate.info WIKI文章 - http://nhibernate.info/doc/howto/various/changing-values-in-nhibernate-events

摘要;使用NHibernate事件模型的审计跟踪通常使用OnPreInsert和OnPreUpdate事件侦听器来更改/修改实体的状态。虽然这确实有效并且被广泛记录为解决方案,但应该注意OnPreInsert和OnPreUpdate事件不是用于更改实体的值,而是应该用于检查值,因此它们返回“否决”。

来自Fabio的更新博文 - http://fabiomaulo.blogspot.com/2011/05/nhibernate-bizarre-audit.html