2009-06-17 10 views
9

LINQ to SQLを使用してDjango's signalsと似たようなことを行う方法を知っている人はいますか?LinqからSqlへの信号?

新しい行が挿入されたときと特定の列が更新されたときに記録しようとしているので、実際にはpre_savepost_saveという信号が必要です。

私は一種の(FooIDが主キーである場合)OnFooIDChanging()OnFooIDChanged()のように定義されたパーシャルを使って、いくつかのモデルでそれを行うことができますが、これは主キーのアイデンティティではない、または設定されている機種では動作しません。コードによって。それらのため

、私はおそらくOnValidate()を使用することができますが、それは唯一のpre_saveだろう、とOnValidate()DBContext.SubmitChanges()から呼び出されているので、それは、タフなデータベースを扱うになり、もちろん二SubmitChanges()から呼び出されることを許可しません私が見る限り、post_saveは基本的に不可能になっています。

答えて

1

[OK]を、私はこの1つ上のウサギの穴の下に完全行ってきたが、私はかなりクールなソリューションを持っていると思う:

まず、あなたのデータコンテキストにイベントハンドラを追加するポストのすべてを収集すること信号を保存してDisposeメソッドを非表示にして、処分する直前にイベントを呼び出すことができます。 (私が代わりにoverridenewキーワードを使用することに注意してください。これは可能なイベントを呼び出すことができます。)

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); 
    } 
} 

次に、LINQ to SQLはあなたのために生成dbmlファイルを検査T4 Templateを書きます。

<# 
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から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); 
    } 

    // ... 
} 

はどこか安全な離れてそれらのファイルを隠すため、誰もがそれを台無しにしようとしません。

シグナルフレームワークが設定されています。これで信号を書くことができます。

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

これは少し複雑なので、何も意味がない場合は、コメントを残して、私はそれに対処するために全力を尽くしますしてください。Signals.csファイルのいずれかでFoo.csまたはすべてで一緒にこれらを入れてください。

1

私はすでにとにかく動作しませんでした投稿何よりもはるかに簡単に解決策を持っている:オーバーライドでSubmitChanges(ConflictMode failureMode):Entity Frameworkのでは

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

、私はあなたがしようとしているものと同様の何かをします目的:エンティティを保存した後、監査のために別のテーブルに新しいエントリを挿入します(変更前のエンティティのコピーです)。変更が保存される前に現在のコンテキストに追加できるSaveChanges()イベントがEFエンティティコンテナ(データコンテキストなど)にあります。