9

有谁知道使用 LINQ to SQL做类似于Django 的事情的方法?signals

我正在尝试记录何时插入新行以及何时更新某些列,所以我真的只想pre_save发出post_save信号。

我可以通过使用像OnFooIDChanging()OnFooIDChanged()(其中FooID是主键)定义的部分来处理某些模型,但这不适用于主键不是标识或由代码设置的模型。

对于那些,我可能会使用OnValidate(),但那只是pre_save,并且它使处理数据库变得困难,因为OnValidate()被调用 from DBContext.SubmitChanges(),这当然不允许SubmitChanges()从内部调用第二个,post_save就我而言基本上是不可能的可以看到。

4

2 回答 2

1

好的,我已经完全放弃了这个,但我认为我有一个非常酷的解决方案:

首先,将事件处理程序添加到您的数据上下文中,该处理程序将收集所有保存后信号并隐藏该Dispose方法,以便我们可以在处理之前立即调用事件。(请注意,我使用new关键字而不是override。这使得调用事件成为可能。)

partial class MyDataContext
{
    internal delegate void PostSaveHandler();
    internal event PostSaveHandler PostSave;

    // This method hides the underlying Dispose because we need to call PostSave.
    public new void Dispose(bool disposing)
    {
        // Obviously necessary error handling omitted for brevity's sake
        PostSave();
        base.Dispose(disposing);
    }
}

接下来,编写一个T4 模板来检查dbmlLinq to Sql 为您生成的文件。

<#
var dbml = XDocument.Load(@"MyDataContext.dbml");
var name = XName.Get("Type", "http://schemas.microsoft.com/linqtosql/dbml/2007");
var tables = from t in dbml.Descendants(name) select t.Attribute("Name").Value;
foreach(var table in tables)
{
#>
    ...

对于数据库中的每个表(以及每个部分类),使用以下方法添加到部分。

public partial class Foo
{
    internal void OnInsert(MyDataContext db) {
        PreInsert();
        db.PostSave += delegate { PostInsert(); };
    }
    internal void OnUpdate(MyDataContext db) {
        PreUpdate();
        db.PostSave += delegate { PostUpdate(); };
    }
    internal void OnDelete(MyDataContext db) {
        PreDelete();
        db.PostSave += delegate { PostDelete(); };
    }
    partial void PreInsert();
    partial void PostInsert();
    partial void PreUpdate();
    partial void PostUpdate();
    partial void PreDelete();
    partial void PostDelete();
}

// repeat for all tables

partial MyDataContext还通过 T4添加另一个。这将为 Linq to SQL 为您提供的部分方法添加定义(如 Merritt 所述)。

public partial class MyDataContext
{
    // Add these three partial methods for each table
    partial void InsertFoo(Foo foo)
    {
        foo.OnInsert(this);
        ExecuteDynamicInsert(foo);
    }
    partial void UpdateFoo(Foo foo)
    {
        foo.OnUpdate(this);
        ExecuteDynamicUpdate(foo);
    }
    partial void DeleteFoo(Foo foo)
    {
        foo.OnDelete(this);
        ExecuteDynamicDelete(foo);
    }

    // ...
}

将这些文件隐藏在安全的地方,这样就没有人试图弄乱它们。

您的信号框架已设置完毕。现在您可以编写信号了。将它们放入Foo.cs或全部放在一个Signals.cs文件中:

partial class Foo
{
    partial void PostInsert()
    {
        EventLog.AddEvent(EventType.FooInserted, this);
    }
}

这有点复杂,所以如果有什么不明白的地方,请发表评论,我会尽力解决它。

于 2009-06-19T02:56:47.060 回答
1

我有一个比我已经发布的解决方案更简单但无论如何都不起作用的解决方案:覆盖 SubmitChanges(ConflictMode failureMode):

partial class MyDataContext
{
     // SubmitChanges() calls this method after inserting default value for param
     public override void SubmitChanges(ConflictMode failureMode)
     {

          // Pre-Submit Changes

          //Updates            
          for (int changeCounter = 0; changeCounter < this.GetChangeSet().Updates.Count; changeCounter++)
          {                
               var modifiedEntity = this.GetChangeSet().Updates[changeCounter];                
               // Do something, for example:
               // var tableXEntry = new TableX() { Prop1 = "foo" };
               // this.tableXEntries.InsertOnSubmit(tableXEntry );
          }            

          //Inserts            
          for (int changeCounter = 0; changeCounter < this.GetChangeSet().Inserts.Count; changeCounter++)            
          {                
               object modifiedEntity = this.GetChangeSet().Inserts[changeCounter];                
               // Do Something
          }


          // Submit Changes
          base.SubmitChanges(failureMode);


          // Post Submit Changes

          //Updates            
          for (int changeCounter = 0; changeCounter < this.GetChangeSet().Updates.Count; changeCounter++)
          {                
               var modifiedEntity = this.GetChangeSet().Updates[changeCounter];                
               // Do something, for example:
               // var tableXEntry = new TableX() { Prop1 = "foo" };
               // this.tableXEntries.InsertOnSubmit(tableXEntry );
          }            

          //Inserts            
          for (int changeCounter = 0; changeCounter < this.GetChangeSet().Inserts.Count; changeCounter++)            
          {                
               object modifiedEntity = this.GetChangeSet().Inserts[changeCounter];                
               // Do Something
          }
}

使用实体框架,我做的事情与您尝试做的事情类似:保存实体后,我将一个新条目插入到另一个表中以进行审计(它是更改之前实体的副本)。EF 实体容器(如数据上下文)上有一个 SaveChanges() 事件,允许您在保存更改之前添加到当前上下文。

于 2009-06-19T14:58:42.580 回答