我创建了以下类,我相信它为某些需要它的表中的数据行提供了一些很好的审计功能。这是我正在使用的课程:
public class AuditableTableServiceEntity : TableServiceEntity
{
protected AuditableTableServiceEntity()
: base()
{
}
protected AuditableTableServiceEntity(string pk, string rk)
: base(pk, rk)
{
}
#region CreatedBy and ModifiedBy
private string _CreatedBy;
[DisplayName("Created By")]
public string CreatedBy
{
get { return _CreatedBy; }
set { _CreatedBy = value; Created = DateTime.Now; }
}
[DisplayName("Created")]
public DateTime? Created { get; set; }
private string _ModifiedBy;
[DisplayName("Modified By")]
public string ModifiedBy
{
get { return _ModifiedBy; }
set { _ModifiedBy = value; Modified = DateTime.Now; }
}
[DisplayName("Modified")]
public DateTime? Modified { get; set; }
#endregion
}
那里的任何人都可以提出我可能会为此课程考虑的任何其他更改。我相信这没关系,但是因为我需要为很多课程实现这一点,我想听听是否有人可以建议任何更改或添加。
答案 0 :(得分:4)
private string _ModifiedBy;
[DisplayName("Modified By")]
public string ModifiedBy
{
get { return _ModifiedBy; }
set { _ModifiedBy = value; Modified = DateTime.Now; }
}
会导致堆栈溢出:在setter中设置属性的值会调用setter,setter设置属性的值,调用setter,依此类推。
您可以在构造函数中设置属性,但是如果实例被序列化和反序列化则会中断:当您反序列化它时,将调用public parameterless构造函数,并调用setter ...将属性设置为对象反序列化的日期和时间,而不是存储的值。
更好的模式可能是为可审计事件创建另一个表。这可能看起来像这样:
public class Audit
{
public string ModifiedBy { get; set; }
public DateTime DateModified { get; set; }
public Type ObjectType { get; set; }
public string Field { get; set; }
public object OldValue { get; set; }
public object NewValue { get; set; }
public static void Record(string user, Type objectType, object oldValue, object newValue)
{
Audit newEvent = new Audit
{
ModifiedBy = user,
DateModified = DateTime.UtcNow, // UtcNow avoids timezone issues
ObjectType = objectType,
OldValue = oldValue,
NewValue = newValue
};
Save(newEvent); // implement according to your particular storage classes
}
}
然后,每当您对要审核的对象进行更改时,请像这样调用Audit.Record()
:
public class SomeKindOfAuditableEntity
{
private string _importantFieldToTrack;
public string ImportantFieldToTrack
{
get { return _importantFieldToTrack; }
set
{
Audit.Record(GetCurrentUser(), this.GetType(), _importantFieldToTrack, value);
_importantFieldToTrack = value;
}
}
}
这样,您可以存储发生在表的所有“有趣”属性中的所有更改的日志。这还有其他一些优点:
主要的缺点是你需要为你感兴趣的每个属性为每个setter添加代码。有一些方法可以通过属性和反射以及面向方面的编程来缓解这种情况 - 例如参见Spring的实现:{ {3}} - 实质上,您要为要跟踪的属性创建属性。
另一个缺点是,您将为审计日志消耗大量存储空间 - 但您可以根据需要定期修改旧条目的后台进程。