C# 实体框架6.1.0 SaveChangesAsync

C# 实体框架6.1.0 SaveChangesAsync,c#,entity-framework,asynchronous,C#,Entity Framework,Asynchronous,我有一个EF帮助器类,它以异步方式保存更改: public async Task<int> SaveOrUpdateAsync<TEntity>(TEntity entity) where TEntity : class, IContextEntity { if (entity.Id == 0) context.Set<TEntity>().Add(entity); else

我有一个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";
)
排队,永远也到不了

 string test = "test";
但如果我将其作为:

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

string test = "test";
)
为什么

Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);
冻结操作,并且永远不会将调用传递到下一行代码(string test=“test”)?

我明白了

这里是正在发生的问题,当您使用“wait”方法等待任务或直接从任务的“result”属性获取结果时,您阻塞了主线程 同时,。当任务最终在线程池中的方法(SaveOrUpdateAsync(TEntity entity))内完成时,它将调用continuation以发回主线程(因为它从未离开过它),因为SynchronizationContext.Current可用并已捕获。但是这里有一个问题:主线程被“Wait”方法阻塞了,这就是为什么我会遇到死锁

为了修复死锁问题,我必须指定不在context.saveChangesSync()的捕获上下文上继续

public异步任务SaveOrUpdateAsync(TEntity实体)
其中tenty:class,i扩展
{
if(entity.Id==0)
context.Set().Add(实体);
其他的
{
tenty dbEntry=context.Set().Find(entity.Id);
如果(dbEntry!=null)dbEntry=entity;
}
返回wait context.SaveChangesAsync().configurewait(continueOnCapturedContext:false);
}
也许我很愚蠢(!),但为什么你的代码会说

if (dbEntry != null) dbEntry = entity;
当然,如果声明应该

if (dbEntry == null) dbEntry = entity;
我想C#null合并操作符也可以用来替换这两行

TEntity dbEntry = context.Set<TEntity>().Find(entity.Id) ?? entity;
tenty dbEntry=context.Set().Find(entity.Id)??实体;
如果没有Task.WaitAll,系统不会阻止当前执行线程,下一行将被执行;如果没有Task.WaitAll,当前线程将等待所有操作完成,然后string test='test';得到正确的执行!但为什么电话总是挂在WaitAll上呢!而且永远不会到达第二行?任务中可能会出现异常,该异常可能永远不会返回,因此它将一直等待,直到数据库中出现死锁或遇到其他错误。我认为上下文不是设计用来从多个线程使用的,因为您可能最终共享一个数据库连接。此外,还需要将更新的实体附加到上下文,而不是像使用dbEntry=entity那样替换引用;如果处于ASP/GUI设置中,则不能使用Task.Wait()或其同级。这将阻止请求/gui线程,这意味着当异步操作完成时,它无法将控制权交还给请求/gui线程,从而导致应用程序死锁。如果要使用
async
,请一直使用它。甚至不要使用Task。等等,只是等待,问题仍然存在。这段代码修复了我的代码。非常感谢。
if (dbEntry != null) dbEntry = entity;
if (dbEntry == null) dbEntry = entity;
TEntity dbEntry = context.Set<TEntity>().Find(entity.Id) ?? entity;