9

DjangoがLINQtoSQLを使用するのsignalsと同じようなことをする方法を知っている人はいますか?

新しい行が挿入されたときと特定の列が更新されたときを記録しようとしているので、本当に必要なpre_saveのはpost_saveシグナルです。

OnFooIDChanging()and OnFooIDChanged()(主キーはここで)のように定義されたパーシャルを使用することで、一部のモデルでそれを行うことができますFooIDが、これは、主キーがIDでないモデル、またはコードによって設定されたモデルでは機能しません。

それらの場合、私はおそらく使用できますOnValidate()が、それだけでありpre_save、データベースの処理が困難になります。これOnValidate()は、から呼び出されるためですDBContext.SubmitChanges()。もちろんSubmitChanges()、内部から1秒を呼び出すことはできず、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);
    }
}

次に、LinqtoSqlが生成するファイルを検査するT4テンプレートを作成します。dbml

<#
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(ConflictModefailureMode)をオーバーライドします:

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

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

于 2009-06-19T14:58:42.580 に答える