web-dev-qa-db-ja.com

新しいDbContext()をいつ作成する必要がありますか

現在、次のようなDbContextを使用しています。

namespace Models
{
    public class ContextDB: DbContext
    {

        public DbSet<User> Users { get; set; }
        public DbSet<UserRole> UserRoles { get; set; }

        public ContextDB()
        {

        }
    }
}

次に、[〜#〜] all [〜#〜]の最上部で次の行を使用しています。データベースにアクセスする必要があるコントローラーです。ユーザーに関連するすべてのメソッドを含むUserRepositoryクラスでも使用しています(アクティブユーザーの取得、ロールの確認など)。

ContextDB _db = new ContextDB();

これについて考えると、1人の訪問者が複数のDbContextをアクティブにできる場合があります。 UserRepositoryを使用するコントローラーを訪問している場合、これは最良のアイデアではない可能性があり、それについていくつか質問があります。

  1. いつ新しいDbContextを作成する必要がありますか、または1つのグローバルコンテキストを渡す必要がありますか?
  2. すべての場所で再利用できるグローバルコンテキストを1つ持つことはできますか?
  3. これによりパフォーマンスが低下しますか?
  4. 他のみんなはどうやってこれをしているの?
66
JensB

派生コントローラーがアクセスできるDataBaseプロパティを公開するベースコントローラーを使用します。

public abstract class BaseController : Controller
{
    public BaseController()
    {
        Database = new DatabaseContext();
    }

    protected DatabaseContext Database { get; set; }

    protected override void Dispose(bool disposing)
    {
        Database.Dispose();
        base.Dispose(disposing);
    }
}

私のアプリケーションのコントローラーはすべてBaseControllerから派生し、次のように使用されます。

public class UserController : BaseController
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(Database.Users.OrderBy(p => p.Name).ToList());
    }
}

質問に答えましょう:

いつ新しいDbContextを作成する必要がありますか、または1つのグローバルコンテキストを渡す必要がありますか?

コンテキストはリクエストごとに作成する必要があります。コンテキストを作成し、必要なことを行ってから削除します。私が使用する基本クラスソリューションでは、コンテキストの使用について心配するだけです。

グローバルコンテキストを試してはいけません(これはWebアプリケーションの動作ではありません)。

1つのグローバルコンテキストをすべての場所で再利用できますか?

いいえ、コンテキストを保持すると、すべての更新、追加、削除などが追跡され、アプリケーションの速度が低下し、かなり微妙なバグがアプリケーションに表示されることさえあります。

おそらくリポジトリを公開することを選択する必要がありますまたは両方のコントローラではなくコンテキストをコントローラに公開します。同じメソッドから2つのコンテキストにアクセスすると、両方のアプリケーションの現在の状態に関する考えが異なる場合、バグが発生します。

個人的には、とにかくDbContextを単純に包むように見えるほとんどのリポジトリの例として、DbContextを直接公開することを好みます。

これによりパフォーマンスが低下しますか?

初めてDbContextが作成されるのは非常に高価ですが、これが完了すると多くの情報がキャッシュされるため、後続のインスタンス化がより速くなります。データベースにアクセスする必要があるたびにコンテキストをインスタンス化するよりも、コンテキストを保持することでパフォーマンスの問題が発生する可能性が高くなります。

他のみんなはどうやってこれをしているの?

場合によります。

一部の人々は、依存性注入フレームワークを使用して、作成時にコンテキストの具体的なインスタンスをコントローラーに渡すことを好みます。両方のオプションで問題ありません。私は、使用されている特定のデータベースが変更されないことがわかっている小規模なアプリケーションにより適しています。

あなたはこれを知らないと主張するかもしれません、そしてそれが依存性注入方法がアプリケーションを変更に対してより弾力的にするのでより良い理由です。これについての私の意見は、おそらく変わらないだろう(SQLサーバーとEntity Frameworkはほとんどあいまいではない)、私の時間は私のアプリケーションに固有のコードを書くのに最も費やされると思う。

74
Benjamin Gale

私は自分の経験から答えようとします。

1。新しいDbContextをいつ作成するか、1つのグローバルコンテキストを渡す必要がありますか?

コンテキストは依存関係の注入によって注入されるべきであり、自分でインスタンス化されるべきではありません。ベストプラクティスは、依存関係の注入によってスコープサービスとして作成することです。 (質問4への私の答えを参照してください)

また、Controller> BusinessLogic> Repositoryのような適切な階層化アプリケーション構造の使用も検討してください。この場合、コントローラーがdb-contextを受信するのではなく、代わりにリポジトリを受信します。コントローラーでdb-contextをインジェクト/インスタンス化すると、アプリケーションアーキテクチャが1か所で多くの責任を兼ね備えていることがわかります。どのような状況でも、私はお勧めできません。

2。すべての場所で再利用する1つのグローバルコンテキストを使用できますか?

はい、できますhaveが、質問は "Should I have ..."->いいえ。コンテキストは、リクエストごとにリポジトリを変更してから再び使用するために使用することを目的としています。

。これによりパフォーマンスが低下しますか?

はい、それはDBContextが単にグローバルであるために作られていないためです。破棄されるまで、入力または照会されたすべてのデータが保存されます。つまり、グローバルコンテキストはどんどん大きくなり、その操作は、メモリ不足の例外が発生するか、すべてクロールが遅くなるために老化するまで、ますます遅くなります。

また、複数のスレッドが同じコンテキストに一度にアクセスすると、例外と多くのエラーが発生します。

4。他のみんなはどうやってこれをしているの?

ファクトリによる依存関係注入によって注入されたDBContext。範囲:

services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));

私の助けがどこにあるのか答えてほしい。

5
Ravior

これは明らかに古い質問ですが、DIを使用している場合は、このようなことを行い、リクエストの有効期間中すべてのオブジェクトをスコープできます

 public class UnitOfWorkAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
            context.BeginTransaction();
        }

        public override void OnActionExecuted(HttpActionExecutedContext actionContext)
        {
            var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
            context.CloseTransaction(actionContext.Exception);
        }
    }
0
CSharper

現在、このアプローチを試しています。これにより、コンテキストを使用しないアクションを呼び出したときにコンテキストをインスタンス化することを回避できます。

public abstract class BaseController : Controller
{
    public BaseController() { }

    private DatabaseContext _database;
    protected DatabaseContext Database
    {
        get
        {
            if (_database == null)
                _database = new DatabaseContext();
            return _database;
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (_database != null)
            _database.Dispose();
        base.Dispose(disposing);
    }
}
0
Andrew