审核添加到 Azure 表存储的行

发布于 2024-12-16 21:55:15 字数 1020 浏览 3 评论 0原文

我创建了以下类,我相信它为我提供了对某些需要它的表中的数据行的一些良好的审核功能。这是我正在使用的课程:

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

}

任何人都可以提出我可能会考虑对该课程进行的任何其他更改吗?我相信这是可以的,但由于我需要在许多课程中实现这一点,我想听听是否有人可以建议任何更改或添加。

I have created the following class which I believe gives me some good auditing capabilities for data rows in certain tables that require it. Here is the class I am using:

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

}

Can anyone out there suggest any additional changes that I might consider for this class. I believe it is okay but as I need to implement this for many classes I would like to hear if anyone can suggest any changes or additions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╭ゆ眷念 2024-12-23 21:55:15
private string _ModifiedBy;

[DisplayName("Modified By")]
public string ModifiedBy
{
    get { return _ModifiedBy; }
    set { _ModifiedBy = value; Modified = DateTime.Now; }
}

会导致堆栈溢出:在setter中设置属性值会调用setter,setter设置属性值,setter又调用setter,等等。

您可以在构造函数中设置属性,但是如果实例被序列化和反序列化,事情就会中断:当您反序列化它时,将调用公共无参数构造函数,并调用 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 的实现这里: http://www.springframework.net/doc-latest/reference /html/aop.html——本质上,您需要为您想要跟踪的属性创建一个属性。

另一个缺点是您将消耗大量的审计日志存储空间 - 但您可以有一个后台进程,根据您的需要定期修剪旧条目。

private string _ModifiedBy;

[DisplayName("Modified By")]
public string ModifiedBy
{
    get { return _ModifiedBy; }
    set { _ModifiedBy = value; Modified = DateTime.Now; }
}

will cause a stack overflow: setting the value of a property in a setter calls the setter, which sets the value of the property, which calls the setter, and so on.

You could set the properties in a constructor, but then things break if an instance is serialized and deserialized: when you deserialize it, the public parameterless constructor is called, and the setter is called... which sets the property to the date and time that the object was deserialized, not the stored value.


A better pattern might be to create another table for auditable events. This might look something like this:

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
    }
}

Then, whenever you make changes to an object you want to audit, call Audit.Record() like so:

public class SomeKindOfAuditableEntity
{
    private string _importantFieldToTrack;

    public string ImportantFieldToTrack
    {
        get { return _importantFieldToTrack; }
        set
        {
            Audit.Record(GetCurrentUser(), this.GetType(), _importantFieldToTrack, value);
            _importantFieldToTrack = value;
        }
    }
}

This way you store a log of all changes that happen to all "interesting" properties of your tables. This has a few other advantages:

  • you see the old and new values of each change
  • the audit log is stored in a different place from the data itself, separating concerns
  • you don't need to have a base class for your data classes
  • the audit for old changes is kept around so you can go back through the entire log of the object's changes

The principal disadvantage is that you need to add code to each setter for each property you're interested in. There are ways to mitigate this with attributes and reflection and aspect-oriented programming -- see for instance Spring's implementation here: http://www.springframework.net/doc-latest/reference/html/aop.html -- in essence, you'd create an attribute for the properties you'd like to track.

The other disadvantage is that you'll consume lots of storage for the audit log - but you can have a background process that trims down the old entries periodically as you see fit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文