2016-05-29 5 views
12

私はこのEntity Frameworkのコアサービスのデフォルトの寿命

services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection)); 

のようにDIを通じてDbContextを登録することができますし、それはその寿命が何であるかを知っているのinterstingていますか?

ここからhttps://github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140 Scopedとして設定されているように見えます。つまり、要求ごとにDbContextインスタンスが作成されます。

質問の最初の部分は次のとおりです。 それは本当ですか?はいの場合は、どのくらいの費用がかかりますか?

2番目の部分は: DbContextを消費し、Controllersで消費されるサービスを作成し、DBの一部のエンティティを管理するAPIを持つサービスをScopedとしても登録する必要がありますか?

答えて

17

はい、DbContextのデフォルトの有効期間が有効です。これは、このように意図されています。

DbContextをインスタンシエートするのはかなり安く、多くのリソースを使用しないようにします。シングルトンの有効期間がDbContextの場合は、特にトラッキングを無効にしない限り、一度読み取ったすべてのレコードはDbContextで追跡されます。これははるかに多くのメモリ使用量を必要とし、それは成長し続けるでしょう。

さらに、DbContextトラックのパフォーマンスが低下します。そのため、DbContextusing(var context = new AppDbContext())ブロック内でのみ使用されることがよくあります。

ウェブアプリケーションでは、frameworkで管理されているので、usingブロックを使用すると問題があります。それを先に処理すると例外が発生して失敗します。

もう一方の側で一時的な有効期間を使用すると、「トランザクション」機能が失われます。スコープ付きの場合、DbContextには要求と同じ長さのトランザクションスコープがあります。

細かい制御が必要な場合は、作業単位パターン(DbContextが既に利用されています)を使用する必要があります。あなたの2番目の質問については

サービスを作成する場合は、スコープの1またはそれより短い(:スコープまたは一時を読む)に等しいのです寿命を持っている必要があります。

サービスの寿命を明示的に指定する必要がある場合は、DbContextファクトリサービスまたはファクトリメソッドをサービスに追加する必要があります。

あなたは

services.AddTransient<Func<AppDbContext>>((provider) => new Func<MyDbContext>(() => new AppDbContext())); 
services.AddSingleton<IMySingletonService, MySingletonService>(); 

のようなものでこれを達成することができ、あなたのサービスは、次のようになります。

public class MySingletonService : IMySingletonService, IDisposable 
{ 
    private readonly AppDbContext context; 

    public MySingletonService(Func<AppDbContext> contextFactory) 
    { 
     if(contextFactory == null) 
      throw new ArgumentNullException(nameof(contextFactory)); 

     // it creates an transient factory, make sure to dispose it in `Dispose()` method. 
     // Since it's member of the MySingletonService, it's lifetime 
     // is effectively bound to it. 
     context = contextFactory(); 
    } 
} 
+2

それは本当に寿命を管理するコントローラのですか?または要求の終わりにリクエストごとにスコープされたものを廃棄するDIですか?私はそれをよりよく理解したいと思います –

+0

私の悪いです。私はフレームワークを言うことを意味しました。コントローラファクトリ( 'IControllerFactory'、デフォルト実装のためのhttps://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Controllers/DefaultControllerFactory.csを参照してください)の' CreateController 'メソッドを呼び出すと、コントローラを作成して処分し、それを破棄し、' ReleaseController() 'メソッドに依存します。内部の動作の詳細とその動作については、このGitHubの問題も参照してください:https://github.com/aspnet/Mvc/issues/3727 – Tseng

+0

ありがとう。コンストラクタ内でDbContextをとるリポジトリがあり、IDisposableを実装すると、それ自体のdisposeメソッドからDbContextでdisposeを呼び出すはずですか?私はアイデンティティのEF UserStoreがdbcontextのdisposeを呼び出さないことに気付きましたが、それは私には間違っていると感じていませんでした。なぜ彼らがなぜそうしたのか理解しようとしていません。 –

4

注:EFのCore 2では、今のプールを作成する新しい方法AddDbContextPoolあり再利用できるコンテキストの数。スコープは変わりませんが、インスタンスは「リセット」されプールに戻されます。私は、「リセット」のオーバーヘッドが新しいものを作成するのと同じであると思っていたでしょうが、そうではないと思います。この方法が使用される場合

、時DbContextインスタンスは、プール内 使用可能なインスタンスがある場合、我々は最初にチェックするコントローラによって を要求されます。リクエスト処理が確定したら、 インスタンスの状態がリセットされ、プールに戻され、インスタンス自体である。+

これは、接続プールが ADO.NETプロバイダで動作し、省電力の利点を持っているかと概念的に類似していますいくつかのDbContextインスタンスの 初期化のコスト。ウェブアプリで

https://docs.microsoft.com/en-us/ef/core/what-is-new/

+0

デリゲートは、大規模なデータベースで時間がかかる「OnModelCreating」関数なのでしょうか? –