简体   繁体   English

实体框架读取查询锁定所有数据库

[英]Entity Framework read queries locking all database

I'm developing a web application using ASP.NET MVC and EF6 to access the database. 我正在使用ASP.NET MVC和EF6开发Web应用程序以访问数据库。

One of the features of my web application allow the user to download a Excel file. 我的Web应用程序的功能之一允许用户下载Excel文件。 The query to get the information from the database takes like 5 seconds and I notice that until the query it's done we can't do anything on the rest of the web application. 从数据库获取信息的查询大约需要5秒钟,我注意到在查询完成之前,我们无法对Web应用程序的其余部分执行任何操作。

Is this the normal behaviour of EF, lock the database even with AsNoTracking on the query? 这是EF的正常行为吗,即使对查询使用AsNoTracking锁定数据库?

If I'm not doing anything wrong and this is the default behaviour of EF how should I resolve this locking problem? 如果我没有做错任何事情,并且这是EF的默认行为,我该如何解决此锁定问题?

(Update) (更新)

I'm using a SQL Server database and the "lock" happens when for exemple I export the excel file and at the same time do a search that uses the same table. 我正在使用SQL Server数据库,例如,当我导出excel文件并同时执行使用相同表的搜索时,就会发生“锁定”。

To organize my code i'm using Repository and UnitOfWork pattern and to create the instances i'm using DI Unity. 为了组织我的代码,我使用存储库和UnitOfWork模式,并使用DI Unity创建实例。

The UnitOfWork implementation: 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;
            }
        }
    }
}

The Repository implementation: 存储库实现:

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

}

The Unity configuration: Unity配置:

    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);

To create my query have to create a extension method like this: 要创建我的查询,必须创建如下扩展方法:

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();
}

If you're downloading a lot of data synchronously it will make the UI freeze up on you. 如果您要同步下载大量数据,它将使UI冻结。 Consider doing this asynchronously. 考虑异步执行此操作。 What are you using client side, anyway? 无论如何,您在使用客户端吗?

I'm assuming you're generating an excel file from data in the database and it's just a matter of it being enough data that it takes ~5 seconds to create the file and send it to the user. 我假设您是从数据库中的数据生成一个excel文件,而这仅仅是因为它有足够的数据,因此需要大约5秒钟的时间来创建文件并将其发送给用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM