我正在开发一个使用ASP.NET MVC和EF6访问数据库的Web应用程序。实体框架读取查询锁定所有数据库
我的web应用程序的一个功能允许用户下载Excel文件。从数据库中获取信息的查询需要5秒钟的时间,我注意到在查询完成之前,我们无法对其他Web应用程序执行任何操作。
这是EF的正常行为,即使在查询上使用AsNoTracking
锁定数据库?
如果我没有做错什么,这是EF的默认行为,我应该如何解决这个锁定问题?
(更新)
我使用的是SQL Server数据库,当我为例导出Excel文件中的“锁定”发生,并在同一时间做,使用相同的表的搜索。
为了整理我的代码,我使用了Repository和UnitOfWork模式,并创建了我使用DI Unity的实例。
的的UnitOfWork实现:
public class UnitOfWork : IUnitOfWork
{
private bool _disposed;
private DbContext _dbContext;
private Dictionary<string, dynamic> _repositories;
private DbContextTransaction _transaction;
public DbContext DbContext
{
get { return _dbContext; }
}
public UnitOfWork(DbContext dbContext)
{
_dbContext = dbContext;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
public IRepository<TEntity> Repository<TEntity>()
{
try
{
if (ServiceLocator.IsLocationProviderSet)
return ServiceLocator.Current.GetInstance<IRepository<TEntity>>();
if (_repositories == null)
_repositories = new Dictionary<string, dynamic>();
var type = typeof(TEntity).Name;
if (_repositories.ContainsKey(type))
return (IRepositoryAsync<TEntity>)_repositories[type];
var repositoryType = typeof(Repository<>);
_repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), this));
return _repositories[type];
}
catch(ActivationException ex)
{
throw new ActivationException(string.Format("You need to configure the implementation of the IRepository<{0}> interface.", typeof(TEntity)), ex);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UnitOfWork()
{
Dispose(false);
}
public void Dispose(bool disposing)
{
if(!_disposed)
{
if(disposing)
{
try
{
_dbContext.Dispose();
_dbContext = null;
}
catch(ObjectDisposedException)
{
//the object has already be disposed
}
_disposed = true;
}
}
}
}
的仓库实现:
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private readonly IUnitOfWork _unitOfWork;
private readonly DbContext _dbContext;
private readonly DbSet<TEntity> _dbSet;
public Repository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbContext = unitOfWork.DbContext;
_dbSet = _dbContext.Set<TEntity>();
}
#region IRepository<TEntity> implementation
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
}
public void Update(TEntity entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
}
public void Delete(TEntity entity)
{
_dbSet.Remove(entity);
}
public IQueryable<TEntity> Queryable()
{
return _dbSet;
}
public IRepository<TEntity> GetRepository<TEntity>()
{
return _unitOfWork.Repository<TEntity>();
}
#endregion
}
的统一配置:
container.RegisterType<DbContext, DbSittiusContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
//Catalog respository register types
container.RegisterType<IRepository<Product>, Repository<Product>>();
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
要创建我的查询必须创建这样的扩展方法:
public static Product FindPublishedAtDateById(this IRepository<Product> repository, int id, DateTime date)
{
return repository.
Queryable().
Where(p => p.Id == id).
Where(p => p.PublishedFrom <= date && (p.PublishedTo == null || p.PublishedTo >= date)).
SingleOrDefault();
}
你可以先分享你正在使用的数据库(oracle,access,sql server等)。然后在数据库中共享EF的已翻译查询以及任何数据库特定信息,如查询计划(如果其Sql Server)。 – Igor
'AsNoTracking'只是意味着如果你没有更新任何内容,EF将不会保持附加到上下文的实体并消除大量的开销。它对执行的查询没有影响。听起来你想运行查询'WITH NOLOCK';在这种情况下,http://stackoverflow.com/questions/926656/entity-framework-with-nolock –
我很确定你的问题与EF和AsNoTracking方法无关。当你执行select语句时,你把共享锁放在表上。它确保其他正在更改数据的操作不能同时执行。在我看来,Web应用程序正在尝试更改正在阅读的表中的数据。尝试启用sql profiler或使用扩展事件来捕获由EF生成的sql查询(我假设你使用SQL Server)。我不建议使用WITH NOLOCK提示,因为它非常危险并可能导致严重问题。 –