实体框架 6.1.0 保存更改异步

本文关键字:保存更改 异步 框架 实体 | 更新日期: 2023-09-27 17:56:45

我有 EF 帮助程序类,可以异步保存更改:

public async Task<int> SaveOrUpdateAsync<TEntity>(TEntity entity)
        where TEntity : class, IContextEntity
    {
        if (entity.Id == 0)
            context.Set<TEntity>().Add(entity);
        else
        {
            TEntity dbEntry = context.Set<TEntity>().Find(entity.Id);
            if (dbEntry != null) dbEntry = entity;
        }
        return await context.SaveChangesAsync();
    }
public void Save()
{
Task saveEntit1Async = repository.SaveOrUpdateAsync<Entity1>(entity1);
Task saveEntity2Async = repository.SaveOrUpdateAsync<Entity2>(entity2);
Task saveEntity3Async =  repository.SaveOrUpdateAsync<Entity3>(Entity3);
Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);
string test = "test";
)

通话卡住

Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);

行,永远无法到达

 string test = "test";

但是如果我运行它:

public void Save()
{
repository.SaveOrUpdateAsync<Entity1>(entity1);
repository.SaveOrUpdateAsync<Entity2>(entity2);
repository.SaveOrUpdateAsync<Entity3>(Entity3);
string test = "test";
)

工作正常,所有更改都被保存,它到达

string test = "test";

为什么

Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);

冻结操作,从不将调用传递到下一行代码(字符串测试 = "test";) ?

实体框架 6.1.0 保存更改异步

我想通了!

这是正在发生的问题,当您使用"等待"方法等待任务或直接从任务的"结果"属性获取结果时,您阻止了主线程与此同时。当任务最终在线程池中的该方法(SaveOrUpdateAsync(TEntity 实体))中完成时,它将调用延续以回发到主线程(因为它从未离开过它),因为 SynchronizationContext.Current 可用并被捕获。但是这里有一个问题:主线程被"等待"方法阻止,这就是我陷入僵局的原因!

为了解决死锁问题,我必须指定不要继续捕获上下文的上下文。SaveChangesAsync().

public async Task<int> SaveOrUpdateAsync<TEntity>(TEntity entity)
        where TEntity : class, IContextEntity
    {
        if (entity.Id == 0)
            context.Set<TEntity>().Add(entity);
        else
        {
            TEntity dbEntry = context.Set<TEntity>().Find(entity.Id);
            if (dbEntry != null) dbEntry = entity;
        }
        return await context.SaveChangesAsync().ConfigureAwait(continueOnCapturedContext: false);
    }

也许我很愚蠢(!),但为什么你的代码说

if (dbEntry != null) dbEntry = entity;

当然,如果语句应该是

if (dbEntry == null) dbEntry = entity;

我想 C# 空合并运算符也可以替换这两行

TEntity dbEntry = context.Set<TEntity>().Find(entity.Id) ?? entity;