C# 与NHibernate一起审核数据库中的记录变更

C# 与NHibernate一起审核数据库中的记录变更,c#,sql-server,nhibernate,audit-trail,C#,Sql Server,Nhibernate,Audit Trail,一、 在我以前的应用程序中,我以以下方式审核数据库中的记录更改: public class AuditEventListener: DefaultDeleteEventListener, IPreUpdateEventListener, IDeleteEventListener { protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntr

一、 在我以前的应用程序中,我以以下方式审核数据库中的记录更改:

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;
        }
    }
对于每个需要的表,我添加了5个字段

  • 罗维德
  • 用户ID
  • 创建日期
  • 变更日期
  • 删除
并添加一个过滤
Deleted=false
并仅输出标准字段的视图

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

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

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

我读过,但不太喜欢有一个重复表的想法:面对现有的记录,旧的似乎和回滚更困难

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

编辑

多亏了Cole W的建议,我实现了NH events listener的方法如下:

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() };
            });
FluentConfiguration=Fluently.Configure()
.数据库(配置)
.Mappings(m=>
{
m、 FluentMappings
.AddFromAssemblyOf();
m、 自动映射。添加(
自动映射组装(新的自动映射配置());
})
.ExposeConfiguration(cfg=>
{
cfg.EventListeners.DeleteEventListeners=
新建DefaultDeleteEventListener[]{new AuditEventListener()};
cfg.EventListeners.PreUpdateEventListeners=
新建IPreUpdateEventListener[]{new AuditEventListener()};
});
我唯一不喜欢的是定义哪些对象需要登录的方式:我不能使用接口,因为我将被迫重新定义所有相关对象中的属性,因此我创建了一个感兴趣的扩展基础对象,但通过这种方式,属性在我的域外变得可见(我不能将其设置为私有或内部,因为数据访问层中的NHibernate必须具有访问权限)

我认为最终的选择是在这条路和这个问题之间,而不是在留下干净的域对象但会在数据库中创建额外表的enver之间
我认为最终的选择是在这条路和这个问题之间,而不是在让我清理我的项目,但会在db中创建附加表的envers之间。如果我要实现这一点,我将使用nhibernates事件侦听器。下面是一篇关于这一点的stackoverflow文章,尽管还有更多附加信息:



lol,这个问题为什么是-1?问题更新和可能的解决方案。如果没有更好的办法,我会将你的答案标记为接受