【问题标题】:NHibernate IPreUpdateEventListener, IPreInsertEventListener not saving to DBNHibernate IPreUpdateEventListener,IPreInsertEventListener 不保存到数据库
【发布时间】:2014-07-23 10:46:24
【问题描述】:

我正在尝试对我的实体实施简单的审核。可审计实体实现了ITimestampable 接口,该接口定义了DateAddedDateModified 属性。

我创建并注册了一个事件监听器来填充这些值。这是完整的代码。

internal class TimeStampEventListener : IPreUpdateEventListener, IPreInsertEventListener
    {
        public bool OnPreUpdate(PreUpdateEvent e)
        {
            if (e.Entity is ITimestampable)
            {
                (e.Entity as ITimestampable).DateModified = DateTime.Now;
            }

            return false;
        }

        public bool OnPreInsert(PreInsertEvent e)
        {
            if (e.Entity is ITimestampable)
            {
                (e.Entity as ITimestampable).DateAdded = DateTime.Now;
            }

            return false;
        }

        public void Register(Configuration configuration)
        {
            configuration.SetListener(ListenerType.PreInsert, this);
            configuration.SetListener(ListenerType.PreUpdate, this);
        }
    }

现在,当我进行会话刷新时,会调用侦听器,正确设置审核属性,但大多数情况下它们不会保存到数据库中。 “大多数时候”我的意思是很少有价值观真正得到持久化。我不确定,但它看起来像应用程序启动后的第一次插入/更新,这更奇怪。

当然,首先我对实体进行了更改,更改是持久化的,但审计属性不是。

当我在分析器中查看生成的 SQL 时,我发现查询中发送的是 NULL 而不是当前时间,所以我猜这不是数据库问题。顺便提一句。我正在使用 MySQL,DateAddedDateModified 列是 DATE 类型。

在 NHibernate 站点上,这些属性仅映射为 <property>。也许我错过了一些针对此类情况的“特殊”映射......?

我完全坚持这一点。任何形式的帮助表示赞赏。

【问题讨论】:

    标签: c# mysql nhibernate orm


    【解决方案1】:

    答案将在 Ayende 文章的引用中隐藏/揭示

    ...然而,微妙之处来了。我们不能只更新实体状态。原因很简单,实体状态是从实体中提取出来的,放在实体状态中,我们对实体状态所做的任何更改都不会反映在实体本身中。这可能导致数据库行和实体实例不同步,并导致一大堆非常讨厌的问题,您不知道从哪里开始调试。

    您必须在这两个事件侦听器中更新实体和实体状态(顺便说一下,其他侦听器不一定是这种情况)。以下是使用这些事件侦听器的简单示例:

    这是同一篇文章中显示如何操作的代码:

    public class AuditEventListener : IPreUpdateEventListener, IPreInsertEventListener
    {
        public bool OnPreUpdate(PreUpdateEvent @event)
        {
            var audit = @event.Entity as IHaveAuditInformation;
            if (audit == null)
                return false;
    
            var time = DateTime.Now;
            var name = WindowsIdentity.GetCurrent().Name;
    
            Set(@event.Persister, @event.State, "UpdatedAt", time);
            Set(@event.Persister, @event.State, "UpdatedBy", name);
    
            audit.UpdatedAt = time;
            audit.UpdatedBy = name;
    
            return false;
        }
    
        public bool OnPreInsert(PreInsertEvent @event)
        {
            var audit = @event.Entity as IHaveAuditInformation;
            if (audit == null)
                return false;
    
    
            var time = DateTime.Now;
            var name = WindowsIdentity.GetCurrent().Name;
    
            Set(@event.Persister, @event.State, "CreatedAt", time);
            Set(@event.Persister, @event.State, "UpdatedAt", time);
            Set(@event.Persister, @event.State, "CreatedBy", name);
            Set(@event.Persister, @event.State, "UpdatedBy", name);
    
            audit.CreatedAt = time;
            audit.CreatedBy = name;
            audit.UpdatedAt = time;
            audit.UpdatedBy = name;
    
            return false;
        }
    

    这里是神奇的Set()

    private void Set(IEntityPersister persister, object[] state
           , string propertyName, object value)
    {
        var index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return;
        state[index] = value;
    }
    

    【讨论】:

    • 是的,做到了。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    相关资源
    最近更新 更多