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

本文关键字:数据库 查询 框架 读取 锁定 实体 | 更新日期: 2023-09-27 17:58:36

我正在开发一个使用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
}

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

要创建我的查询,必须创建这样的扩展方法:

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

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

如果同步下载大量数据,会使UI冻结。请考虑异步执行此操作。不管怎样,你在客户端使用什么?

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