2

Linq to SQLを使用していて、特定のレコードが更新されるたびにテーブルに挿入したいというシナリオがあります。

だから、私が持っているとしましょうTable1、そしてTable2、のレコードTable1が更新されるときはいつでも、私は新しいレコードをに挿入したいと思いTable2ます。

Table1現在、更新されるたびにいくつかのフィールドを更新できる作業コードがあります。これは、次UpdateTable1のように、関数の部分的なメソッドを作成することで実現されています。

partial void UpdateTable1(Table1 instance)
{
   //update some fields
   this.ExecuteDynamicUpdate(instance);
}

Table2これはうまく機能し、非常に便利なので、更新時に新しいレコードが常に作成されるようにするために使用したいと思いTable1ます。ちなみに、これは主にロギングを目的としています。

だからこれは私が次にやろうとしたことです:

partial void UpdateTable1(Table1 instance)
{
   //update some fields
   this.ExecuteDynamicUpdate(instance);
   this.ExecuteDynamicInsert(instance.ConvertToTable2());
}

(ここでは、拡張メソッドを使用して、Table1インスタンスに基づいてTable2レコードを作成しています)

問題は、次のエラーが発生することです。

エンティティは変更追跡されていないため、操作を実行できません。

これを機能させる方法はありますか?

4

2 に答える 2

3

信頼できない回避策を忘れてください(必要に応じて編集履歴を参照してください)。これを実行するためのはるかに信頼性の高い方法を見つけました。

まず、これに部分的なメソッドを使用することを忘れてください(たとえばUpdateTable1、質問で)。インスタンスレコードのみのデータを変更しない限り、これはあまりうまく機能しません。したがって、インスタンス内の関連フィールドを更新する必要がある場合にのみ、これらの部分的なメソッドを保持しています。

SubmitChangesこれを行う方法は、部分DataContextクラスのメソッドをオーバーライドすることです。これにより、デフォルトの処理を許可する前にSubmitChanges(したがって、この機能をロックアウトする前に)、テーブルレコードの挿入/更新/削除が可能になります。

オーバーライド内では、DataContextを使用して現在の変更セットにアクセスできますthis.GetChangeSet()。これにより、すべての変更をループし、必要な追加のテーブル作業(ログレコードの追加など)を実行できます。

以下の例では、と呼ばれる標準のデータベーステーブルがTable1あり、と呼ばれる一致するログテーブルがあると仮定します。内部にTable1Log加えられた変更を記録して、ログテーブルに元のフィールドと同じフィールドがすべて含まれるようにしますが、それを拡張して保存します。 a (変更時)およびa (つまり、追加/編集/削除)。Table1Table1LogDateTimeLogType

これが私の最終的なコードの重要な部分です:

partial class MyDataContext
{

    public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode)
    {

        var set = this.GetChangeSet();//get a list of all pending changes

        foreach (var item in set.Inserts)
        {
            AddLog(item, LogType.Add);
        }
        foreach (var item in set.Updates)
        {
            AddLog(item, LogType.Edit);
        }
        foreach (var item in set.Deletes)
        {
            AddLog(item, LogType.Delete);
        }

        base.SubmitChanges(failureMode);//allow the DataContext to perform it's default work (including your new log changes)

    }

    public void AddLog(object item, LogType logType)
    {

        //some painful type testing, so feel free to refactor this as you wish
        if(item is Table1)
        {
           var log = (item as Table1).ToLog(logType);//ToLog() is an extension method (one for each type)
           this.Table1_Logs.InsertOnSubmit(log);//add the log record ready to be submitted
        }
        else if(item is Table2)
        {
           //same again
        }
        //...repeat for each table class type

    }

}

:if / elseタイプのテストの代替は、ここにあります。私は実際にこれをコードで使用しましたが、非常にうまく機能します。パフォーマンス上の利点があるとは思えませんが、50以上のタイプを切り替える必要がある場合は、読みやすくするのに役立ちます。

于 2012-08-13T15:04:00.340 に答える
0

挿入するには、実際には2つのオプションしかありません。まあ、実際には3。

データベースにトリガーを追加できます。これは、私が働いている場所での変更の追跡に使用します。変更を含むレコードを挿入する更新トリガーがあります。効果的で簡単です。

LINQ to SQLを使用する場合、唯一のオプションは、指定したとおりにテーブルを挿入することです。つまりdb.Table2s.InsertOnSubmit(...)、変更を送信します。

もう1つのオプションは、ログテーブルとエンティティの間に外部キー関係があると仮定して、LINQを介してそのエンティティ関係をSQLに割り当てることです。その後、データコンテキストを参照せずに、ログエンティティを挿入するだけです。

partial void UpdateEntity(Entity instance)
{
    instance.Logs.Add(instance.createLogEntry());
}

このようにすると、データコンテキストへの参照は必要なくなりますが、状況によっては、これがオプションにならない場合があります。

于 2012-08-13T15:20:54.433 に答える