2009-06-17 324 views
9

有谁知道使用LINQ to SQL做类似Django's signals的一些方法?Signin in Linq to Sql?

我想记录何时插入新行,何时更新某些列,所以我真的只想要pre_savepost_save信号。

我可以种做到这一点通过使用像OnFooIDChanging()OnFooIDChanged()(其中FooID是主键)定义的谐音一些模型,但是这并不适用机型,其主要工作重点是不为单位,或设置通过代码。

对于这些,我可能用OnValidate(),但这只会pre_save,它使得与数据库打交道艰难,因为OnValidate()DBContext.SubmitChanges()调用,这当然是不允许第二SubmitChanges()从被称为据我所知,使post_save基本上不可能。

回答

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 Template是考察dbml文件Sql的Linq为您生成。

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

还通过T4添加另一个partial MyDataContext。这将为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); 
    } 
} 

这是一个有点复杂,所以如果有什么是没有意义的,请留言,我会尽我所能来解决它​​。

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()事件(如数据上下文),允许您在保存更改之前添加到当前上下文。