我从数据库加载一个对象/实体:
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
。
我理解为什么我会出现这两个错误,我的问题是:什么样的编码模式最能解决这个问题?
编辑好的,所以上面是一个简化的例子。事实上,函数中还有很多工作要做,所以很难将所有的逻辑从函数中转移到调用方法中。我还希望所有这些工作都是独立的。
Function1
和Function2
更新的item
上的属性是离散的。我使用这个库来确保保存不会覆盖所有字段。
您可以移动代码
db.Entry(item).State = EntityState.Modified;
await db.SaveChangesAsync();
在CCD_ 6。这两个函数的工作是更新该对象的属性。
此外:如果您获取了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});