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块内,您在开始时编写 - 第二个选项风险更大,因为演员不会等待在处理下一条消息之前完成操作,并可能在结果中创建多个范围。

于 2016-09-07T16:24:57.057 回答
1

好吧,我不会使用 DI 容器。:)

一种替代方法是手动管理数据库上下文,而不是“使用(var thing)” - 这可以通过打开连接,完成工作,然后在异步保存后继续,关闭连接,然后 PipeTo 某处别的。

于 2016-09-07T12:06:47.870 回答
0

我最终得到了这个可行的解决方案,它看起来非常好,而且仍然相当简单。我唯一关心的是,如果在其中一个延续中引发异常,它将如何表现,因此将不胜感激。

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 回答