总结我的代码,我有一个使用 IRepository<E>
的 DbContextStrategy<E>
。DbContextStrategy<E>
扩展自 DbContext
并使用 DbSet<E>
对数据库进行 LINQ 操作。E
只是泛型传递的实体类型。
在我的 Web API Controller 中,我使用这个存储库接口(interface)来获取我的资源。
但是,某些实体依赖于其他实体。例如,在 PUT
或 POST
请求中,我应该验证输入的外键以检查它们是否有效。
因此,我需要实例化一个新的 IRepository<X>
,其中 X
是外部实体类型。
为了让我的开发尽可能简单,我生成了一层基类,这些基类将为我处理配置、缓存、依赖注入(inject)和 HTTP 方法绑定(bind)。
在我最小的子 Controller 中,我有以下方法:
/// 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;
}
这是将处理实体更新的方法。基本 Controller 将调用它,然后调用
repository.Edit(entity)
将更新 DbContext
中的实体。操作完成后,IRepository<Season>
就被处理掉了。ValidateShow 是一个私有(private)方法,它只检查
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
方法只是停留在无限循环中。我已经调试了该方法,并且调用正确地委托(delegate)给 DbSet<TVShow>
并且循环发生在: context.Entities.FindAsync(keys)
。该方法工作正常,因为我使用了相同的
ReadAsync
方法来获取 Season
实体。但是当打开两个不同的
DbContext
时,它似乎会产生某种死锁。 ( DbSet<Season>
和 DbSet<TVShow>
)我应该注意到两个
DbContext
都连接到同一个数据库。从 IRepository 到 DbSet 的异步/等待执行流程
IRepository<E>
调用 SelectAsync(keys)
上的 IDao<E>
方法,SelectAsync(keys)
调用 DbContextStrategy<E>
上的 ojit_code 方法。这是代码跟踪:
DefaultRepository : IRepository :
public async Task<E> ReadAsync(params object[] keys) {
if(keys == null || keys.Length < 1) return null;
return await dao.SelectAsync(keys);
}
DefaultDao : IDao
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;
}
DbContextStrategy : IPersistenceStrategy
public async Task<E> SelectAsync(params object[] keys) {
return await context.Entities.FindAsync(keys);
}
最佳答案
DbContext
的每个实例都有自己的事务,这可能会导致死锁,但您需要进行写入操作才能发生这种情况,并且 DbContext 仅在您调用 SaveChanges()
时才将更改保存到数据库中,而您在调用 validatingShow.Wait()
之前不会调用该事务
这个 Wait()
调用更有可能是一个问题。如果您使用 async/await,您应该真正为整个调用堆栈使用 async/await(UpdateEntity()
及以上,包括您的 Web API Controller 的方法)
这里描述了发生这种情况的原因 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
关于c# - 多个 DbContext 会产生死锁吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27230389/