我现在正在使用 IPostUpdateEventListener
接口(interface)进行更新审计日志记录,获取旧值和新值,然后将每个更新的字段存储在“审计”表中以及所有这些。效果很好,但我很难满足最后两个要求:
对于#1,我的第一直觉是使用反射并查找并获取给定实体上的“Employee”属性以找出它是为哪个 Employee 服务的,但是当您处于图表深处的几个对象时,这很快就会分崩离析没有自动返回给定 Employee 对象的方法。
解决 #1 的想法包括要求每个对象都有一个“父”属性,这样我就可以遍历图寻找 Employee 类型(对我来说,这会因为简单的持久性问题而过多地污染我们的域)到使用单独的 SQL遍历外部键并在事后填写员工 ID 的工作(我宁愿不维护单独的 SQL 工作,因为到目前为止一切都是基于代码的 - 并且该 SQL 工作很快就会变得非常讨厌)。
至于第二个要求,我可以得到改变得很好的实际属性名称。对于 80% - 90% 的字段,我们显示的是(格式正确的)属性名称,因此我可以根据 Pascal 大小写分隔名称。但是,由于各种原因,其余字段不匹配。我们正在使用来自 MvcContrib 的 ASP.NET MVC 和 Fluent HTML 构建器,但即使我们将设置修改为在 View 模型上有一个属性覆盖字段名称应该是什么(因此在代码中而不是只是 View ),没有真正的方法可以将 View 模型中的这些属性与正在保存的域对象进行匹配。
这两个问题的最终实用解决方案是在另一个服务中的每次更新操作之后调用审计日志服务,根据需要传入字段名称和员工信息,但是,我真的不想去那里明显原因。
对任一问题的想法将不胜感激。搜索和绞尽脑汁几天没有发现任何用处 - 大多数人似乎停留在简单的旧/新谷记录或只是记录本身的“创建/更新”时间戳。
最佳答案
我有一个和你类似的要求。就我而言,它是一个医疗保健应用程序,审核日志需要确定插入/更新适用的患者。
我的解决方案是定义一个接口(interface),所有被审计的类都需要实现:
public interface IAuditedRecord
{
IPatient OwningPatient { get; }
...
// Other audit-related properties (user, timestamp)
}
被审计的类然后以任何需要的方式实现这个接口(interface)。例如:
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; } }
}
IPostInsertEventListener
和 IPostUpdateEventListener
然后获取 OwningPatient
属性以填充审计记录。该解决方案的优点是将审计逻辑保留在事件监听器中,这是唯一可以确定插入/更新将发生的地方,并且允许遍历对象与其拥有的患者之间的间接链接。
缺点是被审计的类必须从特定的接口(interface)派生。我认为好处大于这个小成本。
关于nhibernate - 复杂的 NHibernate 审计,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1188494/