【问题标题】:capture changes to properties of an object捕获对象属性的更改
【发布时间】:2011-04-18 21:22:08
【问题描述】:

我的应用程序中有多个业务对象(C#、Winforms、WinXP)。当用户在 UI 上执行某些操作时,这些对象中的每一个都会被应用程序的不同部分修改和更新。每次修改后,我需要首先检查发生了什么变化,然后记录对对象所做的这些更改。记录此内容的目的是创建对应用程序中正在进行的活动的全面跟踪。

这些对象中的许多都包含其他对象的列表,并且这种嵌套可以有好几层。任何解决方案的两个主要要求是

  1. 尽可能准确地捕捉变化
  2. 将性能成本降至最低。

例如一个业务对象:

public class MainClass1
{
    public MainClass1()
    {
        detailCollection1 = new ClassDetailCollection1();
        detailCollection2 = new ClassDetailCollection2();
    }

    private Int64 id;
    public Int64 ID
    {
        get { return id; }
        set { id = value; }
    }

    private DateTime timeStamp;
    public DateTime TimeStamp
    {
        get { return timeStamp; }
        set { timeStamp = value; }
    }

    private string category = string.Empty;
    public string Category
    {
        get { return category; }
        set { category = value; }
    }

    private string action = string.Empty;
    public string Action
    {
        get { return action; }
        set { action = value; }
    }

    private ClassDetailCollection1 detailCollection1;
    public ClassDetailCollection1 DetailCollection1
    {
        get { return detailCollection1; }
    }

    private ClassDetailCollection2 detailCollection2;
    public ClassDetailCollection2 DetailCollection2
    {
        get { return detailCollection2; }
    }

    //more collections here
}

public class ClassDetailCollection1
{
    private List<DetailType1> detailType1Collection;
    public List<DetailType1> DetailType1Collection
    {
        get { return detailType1Collection; }
    }

    private List<DetailType2> detailType2Collection;
    public List<DetailType2> DetailType2Collection
    {
        get { return detailType2Collection; }
    }
}

public class ClassDetailCollection2
{
    private List<DetailType3> detailType3Collection;
    public List<DetailType3> DetailType3Collection
    {
        get { return detailType3Collection; }
    }

    private List<DetailType4> detailType4Collection;
    public List<DetailType4> DetailType4Collection
    {
        get { return detailType4Collection; }
    }
}

//more other Types like MainClass1 above...

我可以假设我可以访问对象的旧值和新值。

在这种情况下,我可以想出 2 种方法来尝试做到这一点,而不会被告知发生了什么明确的变化。

  1. 使用反射并遍历对象的所有属性并进行比较 那些有相应的 旧对象的属性。日志 任何已更改的属性。这 方法似乎更灵活,在 如果有的话我不用担心 新属性被添加到任何 对象。但它似乎也表现 重。
  2. 在所有对象的所有属性的设置器中记录更改。 除了这将 需要我修改很多代码,它 似乎更暴力。这将成为;这将是 维护繁重且不灵活,如果 一些人更新任何对象 类型。但这种方式也可能是 表演灯,因为我不会 需要检查发生了什么变化并记录 究竟是什么属性发生了变化。

欢迎提出任何更好的方法和/或改进上述方法的建议

【问题讨论】:

  • 我写了一个基于反射但预编译的单对象(对)比较器来获得答案。所以它可以相对便宜地完成。离开弓,所以不能看 - 但稍后会尝试找到它。

标签: c# enterprise audit


【解决方案1】:

几年前我开发了一个这样的系统。这个想法是跟踪对象的更改并将这些更改存储在数据库中,例如对象的版本控制。

最好的方法称为Aspect-Oriented Programming,或AOP。您将“建议”注入到 setter 和 getter(实际上所有方法执行,getter 和 setter 只是特殊方法),允许您“拦截”对对象执行的操作。查看 Spring.NETPostSharp 以获取 .NET AOP 解决方案。

【讨论】:

  • +1,我想您可以添加一个 IsDirty setter 作为建议。有没有办法为每个属性执行此操作,而无需遍历整个属性列表并附加属性?有没有办法为命名空间中的所有类做到这一点?
【解决方案2】:

我可能无法给你一个好的答案,但我会告诉你,在绝大多数情况下,选项 1 不是一个好的答案。在我们的项目中,我们正在处理一个非常相似的反射式“graph-walker”;在当时似乎是个好主意,但这是一场噩梦,原因如下:

  • 您知道对象已更改,但如果没有在反射“更改处理”类中了解其上方对象的工作原理的高级知识,您可能不知道原因。如果该信息对您很重要,您必须将其提供给更改处理程序,很可能通过域对象上的字段或属性,要求更改您的域并向域传授有关业务逻辑的知识。李>
  • 更改可能会影响多个对象,但可能不需要记录每个级别的更改;例如,当新贷款获得批准时,客户可能不希望在日志中看到借款人未偿还贷款数量的变化,但他们确实希望看到合并导致的变化。在这些情况下管理有关日志记录的规则需要更改处理类了解更多的结构,而不仅仅是一个对象,这会很快使更改处理对象变得非常大而且非常脆弱。
  • Graph walker 的要求可能比你知道的要多;如果你的对象图包含反向引用或交叉引用,walker 必须知道它在哪里,最简单的综合方法是保留它处理的对象列表,并在处理它之前检查当前对象与它处理的对象(使反回溯成为 N^2 操作)。它也不能考虑对图形中对象的更改,这些更改不会在您持久化顶级(非“级联”的引用)时持久化。 NHibernate 使您能够插入自己的图形步行器并遵守映射中的级联规则,这会有所帮助,但是如果您使用的是自己滚动的 DAL,或者您确实想要记录对对象的更改NHibernate 不会级联,您必须自己设置。
  • 处理程序中的一段逻辑可能会进行更改,需要更新“父”对象(也许更新计算字段)。现在,如果更改对更改处理逻辑的另一部分感兴趣,您必须返回并重新评估更改的对象。
  • 如果您有需要创建和持久化新对象的逻辑,您必须做以下两件事之一;将新对象附加到图形的某个地方(步行者可能会或可能不会拾取它),或将新对象持久保存在自己的事务中(如果您使用的是 ORM,则该对象不能引用另一个对象具有“级联”设置的图形,这将导致它首先被保存)。
  • 最后,在遍历图和查找特定对象的“处理程序”时具有高度反射性,将复杂的树传递到这样的框架是保证应用程序减速的保证。

我认为,如果您跳过“更改处理程序”反射模式,并在您正在执行的“工作单元”中包含创建审计日志或任何预持久化逻辑,您会省去很多麻烦在业务层,通过一组“审计记录器”。这允许进行更改的逻辑使用诸如命令或策略之类的算法选择模式来准确地告诉您的审计框架正在发生什么样的更改,因此它可以选择将产生所需日志消息的记录器。

【讨论】:

  • 我最终采用了第二种方法的混合体。我现在保存创建和删除的所有更改,并在数据库中查询对象的先前状态以比较和记录更改。
【解决方案3】:

在这里查看 adempiere 如何进行更改日志:http://wiki.adempiere.net/Change_Log

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-18
    • 2018-12-31
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多