1. ホーム
  2. c#

[解決済み] トランザクションを使用するか、SaveChanges(false)とAcceptAllChanges()を使用するか?

2022-03-15 10:08:13

質問

トランザクションを調査したところ、EFでは、以下をパスしている限り、勝手に処理されるようです。 false から SaveChanges() を呼び出して AcceptAllChanges() は、エラーがなければ

SaveChanges(false);
// ...
AcceptAllChanges();

何か問題が発生した場合、ロールバックする必要はないのでしょうか?それとも、私のメソッドがスコープ外に出た時点で、トランザクションは終了するのでしょうか?

トランザクションの途中で割り当てられたindentiyカラムはどうなるのでしょうか?もし他の人が私のレコードの後にレコードを追加し、私のレコードが不良になった場合、Identityの値が欠落することを意味すると推測される。

標準の TransactionScope クラスを使用することはできますか?

どのように解決するのですか?

Entity Frameworkの場合、ほとんどの場合 SaveChanges() で十分です。これはトランザクションを作成するか、または任意のアンビエントトランザクションに参加し、そのトランザクション内で必要なすべての作業を行います。

時には SaveChanges(false) + AcceptAllChanges() のペアリングが有効です。

最も便利なのは、2つの異なるContextsにまたがって分散トランザクションを行いたい場合です。

すなわち、こんな感じです(悪)。

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save and discard changes
    context1.SaveChanges();

    //Save and discard changes
    context2.SaveChanges();

    //if we get here things are looking good.
    scope.Complete();
}

もし context1.SaveChanges() は成功するが context2.SaveChanges() そのため、失敗を再生したり、効果的にログを記録することができません。

しかし、コードをこのように変更すると。

context1

を呼び出している間に using (TransactionScope scope = new TransactionScope()) { //Do something with context1 //Do something with context2 //Save Changes but don't discard yet context1.SaveChanges(false); //Save Changes but don't discard yet context2.SaveChanges(false); //if we get here things are looking good. scope.Complete(); context1.AcceptAllChanges(); context2.AcceptAllChanges(); } は必要なコマンドをデータベースに送りますが、 コンテキスト自体は変更されないので、必要ならもう一度実行するか、あるいは SaveChanges(false) を使用します。

これは、トランザクションが実際に例外をスローした場合、再試行するか、各コンテキストの状態をログに記録することで補うことができることを意味します。 ObjectStateManager のどこかにあるはずです。

参照 我が ブログ記事 をご覧ください。