多个DbContext会产生死锁吗?

时间:2014-12-01 14:21:01

标签: c# .net asp.net-mvc linq entity-framework

总结我的代码,我有一个使用IRepository<E>的{​​{1}}。

DbContextStrategy<E>DbContextStrategy<E>延伸,并在数据库上使用DbContext进行LINQ操作。

DbSet<E>只是泛型传递的实体类型。

在我的Web API控制器中,我使用此存储库接口来获取我的资源。

但是,某些实体依赖于其他实体。例如,在EPUT请求中,我应验证输入外键以检查它们是否有效。

因此,我需要实例化一个新的POST,其中IRepository<X>是外来实体类型。

为了让我的开发尽可能简单,我生成了一层基类,它将为我处理配置,缓存,依赖注入和HTTP方法绑定。

在我最不好的孩子控制器中,我有以下方法:

X

这是处理实体更新的方法。基本控制器将调用它,然后调用/// Base class provides me with the Season entity fetched from the database. /// An IRepository<Season> is open in the background, and therefore, a DbContext too. protected override Season UpdateEntity(Season entity, SeasonPostDTO dto) { Task<bool> validatingShow = ValidateShow(dto.Show); entity.Number = dto.Number; entity.ReleaseDate = dto.ReleaseDate; entity.Image = dto.Image; entity.TVShowId = dto.Show; entity.BlameUserId = Convert.ToInt32(GetCurrentUserId()); validatingShow.Wait(); if (!validatingShow.Result) throw new EntityNotFoundException("Show not found"); return entity; } ,它将更新repository.Edit(entity)中的实体。在操作之后,DbContext被处理掉。

ValidateShow是一个私有方法,只检查IRepository<Season>是否存在:

showId

但是,private async Task<bool> ValidateShow(int id) { //This will instantiate a new IRepository<TVShow>, and therefore a new DbContext return await UseAsyncDependency<TVShow, bool>(async (showRepo) => { return (await showRepo.ReadAsync(id)) != null; }); } 方法只是处于无限循环中。我调试了该方法,调用被正确委托给ValidateShow,循环发生在:DbSet<TVShow>

该方法正常,因为我使用相同的context.Entities.FindAsync(keys)方法来获取ReadAsync实体。

但是当有两个不同的Season打开时,它似乎会产生某种死锁。 (DbContextDbSet<Season>

我应该注意,DbSet<TVShow>都连接到同一个数据库。

异步/等待从IRepository到DbSet的执行流程

DbContextIRepository<E>上调用SelectAsync(keys)方法,该方法在IDao<E>上调用SelectAsync(keys)方法。

以下是代码跟踪:

DefaultRepository:IRepository

DbContextStrategy<E>

DefaultDao:IDao

public async Task<E> ReadAsync(params object[] keys) {
    if(keys == null || keys.Length < 1) return null;
    return await dao.SelectAsync(keys);
}

DbContextStrategy:IPersistenceStrategy

public async Task<E> SelectAsync(params object[] keys) {
    return await ForEachStrategyAsync(async (strategy) => {
        return await strategy.SelectAsync(keys);
    }, (entity) => {
        return entity != null;
    });
}

private async Task<R> ForEachStrategyAsync<R>(Func<IPersistenceStrategy<E>, Task<R>> function,
                                              Func<R, bool> assertion) {

    R lastResult = default(R);
    foreach(IPersistenceStrategy<E> strategy in strategies) {
         lastResult = await function(strategy);
         if(assertion(lastResult)) break;
    }
    return lastResult;
}

1 个答案:

答案 0 :(得分:3)

DbContext的每个实例都有自己的事务,可能会导致死锁,但是你需要一个写操作才能发生这种情况,而当你调用SaveChanges()时,DbContext只会将更改保存到数据库中在致电validatingShow.Wait()

之前不要打电话

这次Wait()通话更有可能成为问题。如果您正在使用async / await,那么您应该使用async / await作为整个调用堆栈(UpdateEntity()以及包括Web API控制器方法在内的方法)

这里发生了这种情况的原因http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html