1

ASP.NET MVCとEF6を使用してデータベースにアクセスするWebアプリケーションを開発しています。すべてのデータベースをロックするEntity Frameworkの読み取りクエリ

私のWebアプリケーションの機能の1つで、ユーザーはExcelファイルをダウンロードできます。データベースから情報を取得するためのクエリには5秒かかります。クエリが完了するまで、残りのWebアプリケーションでは何もできません。

これはEFの通常の動作ですか、照会でAsNoTrackingの場合でもデータベースをロックしますか?

私が間違ったことをしていない場合は、これがEFのデフォルトの動作です。このロックの問題を解決するにはどうすればよいですか?私は、SQL Serverデータベースを使用していますし、「ロック」exempleのために私は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(); 
} 
+2

使用しているデータベース(oracle、access、sql serverなど)を共有することから始めることができます。 SQL Serverの場合は、クエリープランのようなデータベース固有の情報とともに、データベース内のEFから変換されたクエリーを共有します。 – Igor

+0

'AsNoTracking'は、EFがエンティティをコンテキストに保持しないことを意味し、何かを更新していなければ、多くのオーバーヘッドを排除します。実行されるクエリには関係しません。 'WITH NOLOCK'というクエリを実行したいと思うように聞こえます。その場合、http://stackoverflow.com/questions/926656/entity-framework-with-nolock –

+0

私はあなたの問題がEFとAsNoTrackingメソッドに関係していないことは確かです。 select文を実行すると、共有ロックがテーブルに置かれます。これは、データを変更している他の操作を同時に実行できないことを保証します。私の意見では、Webアプリケーションはあなたが読んでいるテーブルのデータを変更しようとしています。 SQLプロファイラを有効にするか、拡張イベントを使用してEFによって生成されたSQLクエリをキャプチャしてください(SQL Serverを使用していると仮定します)。私はWITH NOLOCKヒントを使用することをお勧めしません。なぜなら、それは本当に危険で大きな問題につながる可能性があるからです。 –

答えて

0

多くのデータを同期してダウンロードすると、UIがフリーズします。これを非同期的に行うことを検討してください。とにかく、あなたは何をクライアント側で使っていますか?

私はデータベースのデータからExcelファイルを生成していると仮定しています。ファイルを作成してユーザーに送信するのに約5秒かかります。

+0

'クライアント側で何を使っているのですか? ' - 第1文で' ASP.NET MVC **とEF6を使ってデータベースにアクセスしているWebアプリケーションを開発しています。また、 'asp.net-mvc'が質問にタグ付けされています。 – Igor

+0

私はブラウザがこのExcelファイルをどのように要求しているのかを知りました。 AJAXが電話しますか?ただのHTMLですか? –

+0

どうしたらいいですか?問題は、なぜこのデータベースコールが実行されるとすぐにウェブサイト上のすべてのリクエストが機能しなくなるのか、なぜそれほど時間がかかるのかということではありません。 – Igor

関連する問題