使用NHibernate审核DB中的记录更改

时间:2014-06-16 10:45:32

标签: c# sql-server nhibernate audit-trail

我,在我过去的应用程序中,我以这种方式审计db中的记录更改:

对于每个需要它的表我添加5个字段

  • 行ID
  • 用户ID
  • CREATEDATE
  • CHANGEDATE
  • 删除

并添加一个过滤Deleted = false并仅输出标准字段

的视图

所有删除和更新操作都是由正确管理这些字段的存储过程完成的:每次更新或删除都会成为一组已删除的标记和创建新记录(仅用于更新)

通过这种方式,我可以简单地访问表格以查看谁和何时进行更改并轻松回滚记录,删除实际结束设置deleted = false到所需的

在我的新应用程序中,我需要类似的东西,但我打算使用Nhibernate,所以我会尽量避免存储过程,还有其他方法可以做到吗?可能没有触发器

我读过How to efficiently version records in an SQL database但不太喜欢这个想法有一个重复的表:面对现有的旧记录并且回滚更难。

我找到了Envers,但它也创建了一个重复的表

修改

感谢Cole W建议我已经实现了NH事件监听器就是这样:

public class AuditEventListener: DefaultDeleteEventListener, IPreUpdateEventListener, IDeleteEventListener
    {
        protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
        {
            if (entity is LoggedEntity)
            {
                var e = (LoggedEntity)entity;
                e.Annullato = true;
                e.DataModifica = DateTime.Now;

                CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);
                CascadeAfterDelete(session, persister, entityEntry, transientEntities);
            }
            else
            {
                base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities);
            }
        }

        public bool OnPreUpdate(PreUpdateEvent eventItem)
        {
            if (eventItem.Entity is LoggedEntity)
            {
                DateTime dataModifica = DateTime.Now;
                store(eventItem.Persister, eventItem.State, "modified_date", dataModifica);
                return false;
            }
            else
                return false;

        }

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

这是一种流利的配置:

        FluentConfiguration configuration = Fluently.Configure()
            .Database(config)
            .Mappings(m =>
                {
                    m.FluentMappings
                        .AddFromAssemblyOf<Class1Map>();
                    m.AutoMappings.Add(
                        AutoMap.AssemblyOf<Class1>(new NHAutoMapConfiguration()));
                })
            .ExposeConfiguration(cfg =>
            {
                cfg.EventListeners.DeleteEventListeners =
                    new DefaultDeleteEventListener[] { new AuditEventListener() };
                cfg.EventListeners.PreUpdateEventListeners =
                    new IPreUpdateEventListener[] { new AuditEventListener() };
            });

我唯一不喜欢的是定义哪些对象需要登录的方法:我不能使用接口,因为我将被迫重新定义所涉及的所有对象中的属性,因此我创建了一个基础感兴趣的对象扩展,但这样,属性在我的域外部变得可见(我不能将它设为私有或内部,因为数据访问层中的NHibernate必须具有访问权限。)

我认为最终选择是在这条道路之间遇到这个问题,而不是那些会让我的域名对象变得干净但会在db中创建额外表格的因素 我认为最终选择是在这条道路上遇到这个问题,而不是那些能让我清理我的项目但会在db中创建额外表格的内容

1 个答案:

答案 0 :(得分:1)

如果我要实现这个,我会使用nhibernates事件监听器。这是一篇关于此的stackoverflow文章,尽管还有更多的附加信息:

How to configure NHIbernate event listeners for Update and Save?
Documentation of NHibernate events and lifecycle?