当使用LINQ-to-SQL时,透明记录对象更改的最佳方法是什么?

4

我记录所有对对象进行的更改,以便用户可以查看并回滚到数据库中任何项目的任何先前版本。

历史数据库表如下:

Item     | ItemId | Field     | WhenChanged         | OldValue | NewValue
customer | 6      | LastName  | 2009-12-31 13:00:04 | Sanders  | Sanders-Smith
customer | 5      | FirstName | 2009-12-31 12:11:14 | Jym      | Jim

目前,每当用户填写一个表单时,我记录这些更改,以便完整地了解对象的旧状态和新状态。

然而,现在我需要使这些历史数据日志从代码中可用。它需要在使用LINQ-to-SQL透明地工作,即开发人员不需要做任何额外的工作,例如以下代码也应该导致将信息写入历史记录表:

using (var db = Datasource.GetContext())
{
    var customers = from c in db.Customers
        where c.Status == "waiting"
        select c;
    foreach(var customer in customers)
    {
        customer.Status = "finished";
    }
}
db.SubmitChanges();

我可以想象有两种方法可以完成这个任务:
  1. 重写 db.SubmitChanges() 方法,但问题是如何访问等待更改的对象。
  2. 将我的日志方法附加到 OnSubmitChanges 事件上,但我还没有找到解决方案。
是否有人曾经处理过这个问题或知道一个好的解决方案?

你能否钩入由Linq to sql-metal设计器或Sql-metal自动生成的INotifyPropertyChanged和INotifyPropertyChanging接口,并在此基础上构建跟踪功能? - Andrew
你有什么理由不能使用数据库触发器吗? - Winston Smith
3个回答

2

针对你的第一个问题,你可以使用db.GetChangeSet()来获取等待更改的对象,并且你可以使用以下方法知道哪些字段发生了变化以及原始值:

ITable table = db.GetTable(entity.GetType());
ModifiedMemberInfo[] modifiedMembers = table.GetModifiedMembers(entity);
object original = table.GetOriginalEntityState(entity);

2
我进行了一些审计更改的类似工作,这是第一步。我的解决方案是通过将设计者上下文抽象化,然后从中派生出真实的上下文并重写SubmitChanges来实现的。它与单独的审计上下文和一个助手类一起工作,该助手类可以接受一个对象并从中构造审计对象。它依赖于属性来提供有关哪个类是特定对象的审计类的必要信息。
您可以在http://farm-fresh-code.blogspot.com找到更多信息。这太复杂了,在此不再重复。

1

由于L2S为您生成代码,而您希望更改生成的代码的行为,我看到两种可能性:

  1. 您可以开始使用T4模板从dbml文件生成代码,并修改模板以添加您的功能。此方法在这里中有描述。
  2. 您可以通过编写自己的部分类将功能添加到生成的(部分)数据上下文类中。在您的部分类中,您可以实现创建/更新/删除方法(CreateCustomer、UpdateCustomer和DeleteCustomer),并添加存储更改的功能。

我希望这些提示能帮助您前进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接