总结我的代码,我有一个使用IRepository<E>
的{{1}}。
DbContextStrategy<E>
从DbContextStrategy<E>
延伸,并在数据库上使用DbContext
进行LINQ操作。
DbSet<E>
只是泛型传递的实体类型。
在我的Web API控制器中,我使用此存储库接口来获取我的资源。
但是,某些实体依赖于其他实体。例如,在E
或PUT
请求中,我应验证输入外键以检查它们是否有效。
因此,我需要实例化一个新的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
打开时,它似乎会产生某种死锁。 (DbContext
和DbSet<Season>
)
我应该注意,DbSet<TVShow>
都连接到同一个数据库。
DbContext
在IRepository<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;
}
答案 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