使用NHibernate在DB中审计记录更改

本文关键字:记录 审计 NHibernate DB 使用 | 更新日期: 2023-09-27 18:08:51

我在过去的应用程序I中审计记录在db中的更改如下:

为每个需要它的表添加5个字段

  • RowID
  • UserId
  • CreateDate
  • ChangeDate

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

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

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

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

我读了如何在SQL数据库中有效地版本记录,但不太喜欢有一个重复表的想法:面对旧的记录和回滚更困难。

我找到了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

使用NHibernate在DB中审计记录更改

中创建额外的表

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

如何配置NHIbernate事件监听器更新和保存?
NHibernate事件和生命周期的文档?