0

AKKA.NET 受信関数内で SaveChangesAsync を使用してデータベースに変更を保存する際に問題があります。誰かが何が起こっているのか説明できますか?

詳細: 私はこの受信ブロックを持っています:

Receive<UpdateUnitVM>((msg) => {
                using (var scope = AutofacDependencyContainer.Current.CreateTenantScope(new TenantId(msg.UnitConfiguration.TenantId)))
                {
                    var db = scope.GetService<ApplicationDbContext>();

                    ...work on some objects inside the db context

                    //now save and continue with next actor using PipeTo
                    var continueFlags = TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously;
                    db.SaveChangesAsync().ContinueWith(myint => new UnitConditionRuleGuard.UnitChanged(msg.UnitConfiguration.GetTenantUnitPair()), continueFlags).PipeTo(unitConditionRuleGuard);
                }
            });

このように SaveChanges を使用するようにコードを変更すると、機能します。

Receive<UpdateUnitVM>((msg) => {
                using (var scope = AutofacDependencyContainer.Current.CreateTenantScope(new TenantId(msg.UnitConfiguration.TenantId)))
                {
                    var db = scope.GetService<ApplicationDbContext>();

                    ...work on some objects inside the db context

                    //now save (blocking) and continue with next actor sequentially
                    db.SaveChanges();
                    unitConditionRuleGuard.Tell(new UnitConditionRuleGuard.UnitChanged(msg.UnitConfiguration.GetTenantUnitPair()));
                }
            });

using-block は新しい Autofac 依存関係注入コンテナー スコープを作成するため、using ブロックが終了すると、db-object が破棄されることに注意してください。これが問題だと感じています。ただし、それについて何をすべきか、dbcontext-object の有効期間を適切に延長する方法がわかりません。

4

3 に答える 3

3

SaveChangesAsync+を使用するContinueWithことは、変更の保存が完了するのを待つことと同じではありません。そこで行っているのは、後続の操作で非同期呼び出しを行い、変更を保存する前にデータベース コンテキストを破棄することです。

ReceiveAsyncハンドラーを使用await db.SaveChangesAsync();して完了するか、using { .. }ブロックを破棄して代わりに明示的にスコープを破棄することで修正できますContinueWith。最初に書いたように、ブロック内で-アクターが待機しないため、2番目のオプションはより危険です次のメッセージを処理する前に操作が完了するため、結果に複数のスコープが作成される場合があります。

于 2016-09-07T16:24:57.057 に答える
1

まあ、DIコンテナは使いません。:)

1 つの代替方法は、'using (var thing)' ではなく、手動で db コンテキストを管理することです。これは、接続を開いて作業を行い、非同期で保存した後、接続を閉じてから PipeTo のどこかに接続することで機能します。そうしないと。

于 2016-09-07T12:06:47.870 に答える
0

私はこの実用的なソリューションに行き着きました。これはかなり良いようで、それでもかなりシンプルです。私の唯一の懸念は、例外が継続の1つでスローされた場合にどのように動作するかということです。そのため、さらにコメントをいただければ幸いです。

Receive<UpdateUnitVM>((msg) => {
                var scope = AutofacDependencyContainer.Current.CreateTenantScope(new TenantId(msg.UnitConfiguration.TenantId));

                var db = scope.GetService<ApplicationDbContext>();

                ...work on some objects inside the db context...

                //now save and continue with next actor using PipeTo
                var continueFlags = TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously;
                db.SaveChangesAsync()
                   .ContinueWith(...transform message..., continueFlags)
                   .PipeTo(...some other actor...)
                   .ContinueWith(x => scope.Dispose(), continueFlags);
            }
        });
于 2016-09-08T08:23:00.070 に答える