EF6:在异步任务中使用dbContext保存到同一实体



我从数据库加载一个对象/实体:

var db = new DbContext();
//...
var item = db.Items.First();

然后我想执行两个异步任务,当返回时,更新项目上的数据:

var task1 = Function1(db, item); 
var task2 = Function2(db, item); 
await Task.WhenAll(new Task[] { task1 , task2 });

这两个函数将有一些代码,用于获取、设置&在项目上保存一个(不同的(属性,如下所示:

var orderId = await CallApi();
item.OrderId = orderId;
db.Entry(item).State = EntityState.Modified;
await db.SaveChangesAsync();

然而,由于它们是异步运行的,我得到了错误:A second operation started on this context before a previous asynchronous operation completed

我尝试在函数中新建一个dbContext,但随后出现错误An entity object cannot be referenced by multiple instances of IEntityChangeTracker

我理解为什么我会出现这两个错误,我的问题是:什么样的编码模式最能解决这个问题?


编辑好的,所以上面是一个简化的例子。事实上,函数中还有很多工作要做,所以很难将所有的逻辑从函数中转移到调用方法中。我还希望所有这些工作都是独立的。

Function1Function2更新的item上的属性是离散的。我使用这个库来确保保存不会覆盖所有字段。

您可以移动代码

db.Entry(item).State = EntityState.Modified; 
await db.SaveChangesAsync();

在CCD_ 6。这两个函数的工作是更新该对象的属性。

不要让两个线程在同一个dbContext上执行操作。dbContext跟踪提取的项。如果两个线程同时获取和更改同一DbContext上的项,可能会导致不希望的结果。

此外:如果您获取了Item,只需更改所需的属性即可。您不需要将状态设置为"已修改"。dbContext可以检查它是否具有原始值。

因此,创建创建自己的DbContext的函数,获取请求的数据,更改数据,保存数据,最后处理DbContext。

async Task Function1(...)
{
using (var dbcontext = new MyDbContext(...))
{
// Start Fetching the item that must be changed; don't await yet
var taskFetchItemToChange = dbContext.Items
.Where(...)
.FirstOrDefaultAsync();
// Start fetching the orderId that must be changed; don't await yet
var taskFetchOrderId = this.CallApiAsync();
// await until both item and orderId are fetched:
await Task.WhenAll(new Task[] {taskFetchItemToChange, taskFetchOrderId});
var fetchedItemToChange = taskFetchItemToChange.Result;
var fetchedOrderId = taskFetchOrderId.Result;
fetchedItemToChange.OrderId = fetchedOrderId;
// or do this in one big unreadable unmaintainable untestable step
await dbContext.SaveChangesAsync();
}
}

您将具有类似的Function2,或者可能具有不同参数的相同Function1。

var taskFunction1 = Function1();
var taskFunction2 = Function2();
await Task.WhenAll( new Task[] {taskFunction1, taskFunction2});

最新更新