锁定DbContext以在EF6中完成操作

时间:2017-11-16 14:12:19

标签: entity-framework-6 task-parallel-library

我的业务逻辑层中有一些代码,它们使用一些存储库,这些存储库又使用DbContext(在数据层中)。大多数代码都是异步的。在我的业务逻辑中的某个时刻,我立刻调用了几个存储库的异步方法(Task.WhenAll...)) 我遇到了错误A second operation started on this context before a previous asynchronous operation completed

我的观点是,业务逻辑不应该关心/了解存储库如何完成它们的工作,所以它应该能够在异步任务上使用并行性,如果“它会如此”。

所以我希望能够以A second operation应该等到previous asynchronous operation完成的关键时刻以异步/等待友好的方式锁定。

如何做到这一点?

当前的工作环境:忘记任务。什么时候使用等待,就像TPL一样甚至不存在

        var postsResult = await _IUserLogic.GetActivePostsAsync();
        var usersResult = await _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId);

代码

        var postsTask = _IUserLogic.GetActivePostsAsync();
        var usersTask = _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId);
        await Ask.WhenAll(postsTask , usersTask );
        var postsResult = postsTask.Result;
        var usersResult = usersTask.Result;

1 个答案:

答案 0 :(得分:1)

每个线程都需要自己的DbContext,因为DbContext不是线程安全的。但是,这里有一些解决方法。

  1. 每个存储库都有自己的新DbContext。这样,每个人在自己的线程上都有自己的实例。如果您需要将此作为单个事务,则可以使用事务范围(最新版本允许异步调用)。
  2. 业务层将dbcontext传递到每个存储库,并在最后调用一次保存更改。每个存储库只是将他们的数据添加到DbSets中,最后只有一个调用。
  3. (Worst)在你的实例中覆盖DbContext上的SaveChanges并创建你自己的lock()所以所有这些都经过那里。然而,他几乎击败了Task.WhenAll的目的,因为无论如何你一次只能保存一个。
  4. 做你做过的事并单独给他们打电话。