复杂的NHibernate审计

时间:2009-07-27 14:28:21

标签: nhibernate auditing

我正在使用IPostUpdateEventListener界面立即执行更新审核日志记录,获取旧值和新值,然后将每个更新的字段存储在“审核”表和所有jive中。工作膨胀,但最后两个要求我很难满足:

  1. 显示更新所针对的员工。
  2. 显示已更新字段的“友好”名称。
  3. 对于#1,我的第一直觉是使用反射并寻找&获取给定实体上的“Employee”属性以找出它所属的Employee,但是如果您在图中没有自动方式返回给定的Employee对象,那么很快就会崩溃。

    解决#1的想法远远不是要求每个对象都有一个“父”属性,所以我可以遍历图表,寻找雇员类型(对我而言,对于一个简单的持久性问题而言,这会过多地污染我们的域)一个单独的SQL作业来转换foriegn键并在事后填写Employee ID(我宁愿不维护一个单独的SQL作业,因为everthing是迄今为止基于代码的 - 而且SQL作业会很快变得非常讨厌)。 / p>

    至于第二个要求,我可以得到改变的实际属性名称。对于80%-90%的好字段,(格式正确的)属性名称是我们显示的属性,因此我可以根据Pascal大小写来区分名称。然而,由于各种原因,其余的字段不匹配。我们正在使用来自MvcContrib的ASP.NET MVC和Fluent HTML构建器,但即使我们将设置修改为在视图模型上具有覆盖字段名称应该是什么的属性(并因此在代码中使用它而不是只是视图),没有真正的方法可以将视图模型中的属性与要保存的域对象进行匹配。

    这两个问题的最终实用解决方案就是在另一个服务中的每个更新操作之后调用审计日志服务,根据需要传递字段名称和员工信息,但是,我真的不想去有明显的原因。

    非常感谢任何一个问题的想法。搜索和劫持我的大脑几天没有任何用处 - 大多数人似乎停止在简单的旧/新谷值录音或只是记录本身的“创建/更新”时间戳。

4 个答案:

答案 0 :(得分:3)

我的要求与您的要求相似。就我而言,它是一个医疗保健应用程序,审核日志需要识别插入/更新适用的患者。

我的解决方案是定义一个接口,所有审计类都需要实现该接口:

public interface IAuditedRecord
{
    IPatient OwningPatient { get; }

    ...
    // Other audit-related properties (user, timestamp)
}

然后,审计类以任何方式实现此接口。例如:

public class Medication : IAuditedRecord
{
    // One end of a bidirectional association. Populated by NHibernate.
    private IPatient _patient;

    IPatient OwningPatient { get { return _patient; } }
}

public class MedicationNote : IAuditedRecord
{
    // One end of a bidirectional association. Populated by NHibernate.
    private Medication _medication;

    IPatient OwningPatient { get { return _medication.OwningPatient; } }
}

IPostInsertEventListenerIPostUpdateEventListener然后获取OwningPatient属性以填充审核记录。

该解决方案的优点是将审计逻辑保留在事件侦听器中,这是唯一可确保插入/更新发生的位置,并允许遍历对象与其之间的间接链接拥有病人。

缺点是审计类必须从特定接口派生。我认为好处超过了这个小成本。

答案 1 :(得分:0)

这似乎比一个简单的审计跟踪更复杂,因此我倾向于使用应用程序服务来处理这个问题。

  1. 它更容易测试。
  2. 明确的。
  3. 您不必诉诸反射或共同财产。
  4. 我们在我们的应用程序中使用审计服务,即使我们的场景比您的场景简单得多,因为它涉及到域名。我们的域知道关于历史记录并使用历史记录,它不是仅为某些报告前端创建的。

    您是在记录谁(员工)正在进行更新,还是员工某种聚合根?

答案 2 :(得分:0)

对于#1,我设计了以下内容: 在MyCommon程序集中,我声明了

public interface IUserSessionStore
{
    UserSession Get();
    void Set(UserSession userSession);
}

使用Ninject按请求创建。这个类的实现只是将UserSession对象存储在ASPNET MVC Session中。

有了这个,我可以在所有层中请求IUserSessionStore,并获取此类使用的UserSession,并在每个对象中插入审计信息(下面的类将在MyModel项目中):

public class AuditUpdater : DefaultSaveOrUpdateEventListener
{
    private IUserSessionStore userSessionStore;
    public AuditUpdater(IUserSessionStore userSessionStore)
    {
        this.userSessionStore = userSessionStore;
    }

    private Guid GetUserId()
    {
        return userSessionStore.Get().UserId;
    }

    private void UpdateAuditCreate(IAuditCreate auditable)
    {
        if (auditable != null)
        {
            auditable.CreationDate = DateTime.UtcNow;
            auditable.CreatedBy = GetUserId();
        }
    }

    .......
}

因此,您可以对此进行调整以获取所需的员工信息。

很高兴我会提出更多建议!

答案 3 :(得分:0)

要创建日志,您可以使用IPostInsertEventListener或IPostUpdateEventListener。  如果您使用的是流畅配置,则可以按照下面的示例进行配置。

  

具有发布或更新提交时将调用事件。

.ExposeConfiguration(c => c.EventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] { new AuditEventPostInsert() })
.ExposeConfiguration(c => c.EventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] { new AuditEventPostUpdate() });