我的应用程序中有多个业务对象(C#、Winforms、WinXP)。当用户在 UI 上执行某些操作时,应用程序的不同部分会修改和更新每个对象。每次修改后,我需要首先检查发生了什么变化,然后记录对对象所做的这些更改。记录此信息的目的是创建对应用程序中正在进行的活动的全面跟踪。
这些对象中的许多对象都包含其他对象的列表,并且这种嵌套可以是几层深。任何解决方案的两个主要要求是
- 尽可能准确地捕捉变化
- 将性能成本降至最低。
例如,对于业务对象:
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...
我可以假设我将有权访问该对象的旧值和新值。
在这种情况下,我可以想出两种方法来尝试执行此操作,而无需告知已明确更改的内容。
- 使用反射并迭代对象的所有属性并进行比较
那些具有相应的
旧对象的属性。日志
任何已更改的属性。这
方法似乎更加灵活,
我不必担心如果有的话
新属性被添加到任何
对象。但看起来也有性能
很重。
- 记录所有对象所有属性的设置器中的更改。
除了这将
需要我改很多代码,它
看起来更暴力。这将是
维护工作繁重且不灵活,如果
有人更新任何对象
类型。但这样也可能是
性能轻,因为我不会
需要检查更改的内容并记录
究竟更改了哪些属性。
欢迎提出任何更好的方法和/或改进上述方法的建议
I have multiple business objects in my application (C#, Winforms, WinXP). When the user executes some action on the UI, each of these objects are modified and updated by different parts of the application. After each modification, I need to first check what has changed and then log these changes made to the object. The purpose of logging this is to create a comprehensive tracking of activity going on in the application.
Many among these objects contain contain lists of other objects and this nesting can be several levels deep. The 2 main requirements for any solution would be
- capture changes as accurately as possible
- keep performance cost to minimum.
eg of a business object:
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...
I can assume that I will have access to the old values and new values of the object.
In that case I can think of 2 ways to try to do this without being told what has explicitly changed.
- use reflection and iterate thru all properties of the object and compare
those with the corresponding
properties of the older object. Log
any properties that have changed. This
approach seems to be more flexible, in
that I would not have to worry if any
new properties are added to any of the
objects. But it also seems performance
heavy.
- Log changes in the setter of all the properties for all the objects.
Other than the fact that this will
need me to change a lot of code, it
seems more brute force. This will be
maintenance heavy and inflexible if
some one updates any of the Object
Types. But this way it may also be
preformance light since I will not
need to check what changed and log
exactly what properties are changed.
Suggestions for any better approaches and/or improvements to above approaches are welcome
发布评论
评论(3)
几年前我开发了一个这样的系统。这个想法是跟踪对象的更改并将这些更改存储在数据库中,就像对象的版本控制一样。
最好的方法称为面向方面编程,或AOP。您将“建议”注入到 setter 和 getter 中(实际上所有方法执行,getter 和 setter 都只是特殊方法),允许您“拦截”对对象执行的操作。查看 Spring.NET 或 PostSharp 用于 .NET AOP 解决方案。
I developed a system like this a few years ago. The idea was to track changes to an object and store those changes in a database, like version control for objects.
The best approach is called Aspect-Oriented Programming, or AOP. You inject "advice" into the setters and getters (actually all method execution, getters and setters are just special methods) allowing you to "intercept" actions taken on the objects. Look into Spring.NET or PostSharp for .NET AOP solutions.
我可能无法给你一个好的答案,但我会告诉你,在绝大多数情况下,选项 1 并不是一个好的答案。在我们的项目中,我们正在处理一个非常相似的反思性“graph-walker”;当时看起来是一个好主意,但它是一场噩梦,原因如下:
我认为,如果您跳过“更改处理程序”反射模式,并在您在业务中执行的“工作单元”中包含审核日志的创建或任何预持久性逻辑,您将为自己省去很多麻烦层,通过一组“审计记录器”。这允许进行更改的逻辑采用算法选择模式(例如命令或策略)来告诉您的审计框架到底发生了哪种更改,以便它可以选择将生成所需日志记录消息的记录器。
I may not be able to give you a good answer, but I will tell you that in the overwhelming majority of cases, option 1 is NOT a good answer. We're dealing with a very similar reflective "graph-walker" in our project; seemed like a good idea at the time, but it is a nightmare, for the following reasons:
I think you'll save yourself a lot of headaches if you skip the "change handler" reflective pattern, and include the creation of audit logs or any pre-persistence logic in the "unit of work" you're performing up at the business layer, through a set of "audit loggers". This allows the logic making the changes to employ an algorithm selection pattern such as Command or Strategy to tell your audit framework exactly what kind of change is happening, so it can pick the logger that will produce the required logging messages.
请参阅此处 adempiere 如何完成变更日志:http://wiki.adempiere.net/Change_Log
See here how adempiere did the changelog: http://wiki.adempiere.net/Change_Log