LoginSignup
32
23

More than 5 years have passed since last update.

Entity Framework の DB 接続の解放について、 using した場合と DI コンテナを使った場合の違い。

Last updated at Posted at 2018-11-26

はじめに

今更ながら、Entity Framework の DB 接続の解放方法について、usingステートメントを使用した場合と ASP.NET Core 組み込みの DI コンテナを使った場合の違いについて調べました。

外部リソースの解放について

DB 接続など.NETの管理外の外部リソース1は、使い終わったら破棄する必要があります。
EF Coreでは DbContextを継承したクラスを使用してDB 接続を行います。

FooDbContext.cs
public class FooDbContext : DbContext {
  public FooDbContext(DbContextOptions<FooDbContext> options) :base(options) { }
  public DbSet<BarEntity> BarEntities { get; set; }
}

DB 接続を破棄するにはDbContext.Disposeメソッドを呼び出します。

確実にDisposeするには、

  • usingステートメントを使用する
  • フレームワークASP.NET Coreの DI コンテナに任せる

方法があります。2

usingステートメントで外部リソースの破棄する

usingステートメントを使用するとブロック{}を抜けた際に自動でDisposeが呼ばれます。
途中でreturnしたり、例外がスローされても確実にDisposeされます。

アプリケーションでDbContextを使用する場合、後述のASP.NET Coreの DI コンテナに任せるので、usingはユニットテストなどで使用することが多いです。

using (var dbContext = new FooDbContext()) {
  var bars = dbContext.BarEntities.ToLoist();
  return bars;
} // <- ここで FooDbContext.Dispose() される

ASP.NET Coreの DI コンテナに破棄を任せる

ASP.NET Coreの DI コンテナを使用すると、DbContextのインスタンスの管理はフレームワークに任されます。
DI されたDbContextのインスタンスのライフタイムは利用側のスコープと同等で、利用側のスコープを抜けた時にDbContext.Disposeが呼ばれます。3

DI コンテナにDbContextを設定するにはStartupクラスでAddDbContextを使います。

Startup.cs
public void ConfigureServices(IServiceCollection services) {
  services.AddDbContext<FooDbContext>(options => {
    options.UseSqlServer("接続文字列");
  });
}

データベースコンテキストを利用するクラスのコンストラクタでDbContextを引数にとるとDbContextのインスタンスが DI コンテナによって注入されます。
以下のBarsControllerのインスタンスが破棄された時に自動でDbContextDisposeが呼ばれ破棄されます。

public class BarsController {
  readonly FooDbContext dbContext;
  public BarsController(FooDbContext fooDbContext) {
    dbContext = fooDbContext;
  }
  ...
}

注意点

DI コンテナーで注入したデータベースコンテキストをusingDispose)してはいけません。
インスタンスが破棄されたにも関わらず、DI コンテナー側でDisposeが呼ばれて例外が発生します。


  1. 不要なオブジェクトは.NETのガーベジコレクタによって破棄されますが、DB 接続やファイル IO は明示的にリソースを開放する必要があります。 

  2. try {...} finally {...}finallyブロックでDbContext.Dispose()しでも確実に破棄できます。 

  3. ライフタイムがシングルトンでない理由はASP.NET Coreが一度読んだレコードを(AsNoTrackingで無効にしない限り)変更を感知するために追跡し、メモリが膨れるためです。 

32
23
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
23