实体框架6.1.0 SaveChangesAsync

时间:2014-04-04 16:19:49

标签: 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
        {
            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);

冻结操作并且永远不会将调用传递给下一行代码(字符串测试=&#34;测试&#34 ;;)?

2 个答案:

答案 0 :(得分:14)

我明白了!

以下是发生的问题,当您使用“等待”方法等待任务或直接从任务的“结果”属性获取结果时,您阻止主线程 同时。当最终任务在线程池中的该方法(SaveOrUpdateAsync(TEntity entity))内完成时,它将调用continuation以回发到主线程(因为它从未离开它),因为SynchronizationContext.Current可用并被捕获。但这是一个问题:主线程被“等待”方法阻止,这就是我陷入僵局的方式!

要修复死锁问题,我必须指定不继续捕获context.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);
    }

答案 1 :(得分:0)

也许我是傻瓜(!),但为什么你的代码会说

if (dbEntry != null) dbEntry = entity;

肯定if语句应该是

if (dbEntry == null) dbEntry = entity;

我猜C#null-coalescing运算符也可以替换两行

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