1

我正在开发一个使用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(); 
} 
+2

你可以先分享你正在使用的数据库(oracle,access,sql server等)。然后在数据库中共享EF的已翻译查询以及任何数据库特定信息,如查询计划(如果其Sql Server)。 – Igor

+0

'AsNoTracking'只是意味着如果你没有更新任何内容,EF将不会保持附加到上下文的实体并消除大量的开销。它对执行的查询没有影响。听起来你想运行查询'WITH NOLOCK';在这种情况下,http://stackoverflow.com/questions/926656/entity-framework-with-nolock –

+0

我很确定你的问题与EF和AsNoTracking方法无关。当你执行select语句时,你把共享锁放在表上。它确保其他正在更改数据的操作不能同时执行。在我看来,Web应用程序正在尝试更改正在阅读的表中的数据。尝试启用sql profiler或使用扩展事件来捕获由EF生成的sql查询(我假设你使用SQL Server)。我不建议使用WITH NOLOCK提示,因为它非常危险并可能导致严重问题。 –

回答

0

如果您正在同步下载大量数据,它会使UI冻结在您身上。考虑这样做异步。无论如何,你在使用客户端?

我假设你是从数据库中的数据生成一个excel文件,它只是一个足够的数据,它需要约5秒钟来创建文件并将其发送给用户。

+0

'你在用什么客户端,无论如何?' - 第一句话在后'我正在开发一个使用ASP.NET MVC **和EF6访问数据库的Web应用程序。另外'asp.net-mvc'在问题中被标记。 – Igor

+0

我的意思是浏览器如何请求这个Excel文件。 AJAX调用?只是简单的HTML? –

+0

那会怎么样?问题不在于为什么在这个数据库调用执行之后,为什么网站上的所有请求都停止工作。 – Igor