SaveChangesAsync在AKKA.NET的接收块中不起作用

时间:2016-09-07 07:13:53

标签: .net akka akka.net actor-model

我在使用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对象的生命周期。

3 个答案:

答案 0 :(得分:3)

使用SaveChangesAsync + ContinueWith与等待保存更改完成不同。你在那里做的是与后续操作进行异步调用,然后在完成之前处理数据库上下文以保存更改。

您可以使用ReceiveAsync处理程序并使用await db.SaveChangesAsync();来完成修复,或者通过抛出using { .. }块并在ContinueWith内明确处置范围来解决问题块,你在开头写的 - 第二个选项风险更大,因为actor在处理下一条消息之前不会等待操作完成,并且可能会在结果中创建多个范围。

答案 1 :(得分:1)

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

一种替代方法是手动管理数据库上下文,而不是使用(var thing)&#39; - 这可以通过打开连接,完成工作,然后在异步保存后继续,关闭连接,然后PipeTo到其他地方。

答案 2 :(得分: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);
            }
        });