87

私は現在DbContextこれに似たものを使用しています:

namespace Models
{
    public class ContextDB: DbContext
    {
              
        public DbSet<User> Users { get; set; }
        public DbSet<UserRole> UserRoles { get; set; }

        public ContextDB()
        {
            
        }
    }
}

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

ContextDB _db = new ContextDB();

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

いつ新しいDbContextを作成する必要がありますか?または、すべての場所で渡されて再利用される1つのグローバルコンテキストが必要ですか?それはパフォーマンスの低下を引き起こしますか?これを行う別の方法の提案も歓迎します。

4

6 に答える 6

86

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

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

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

他のみんなはどうやってこれをやっていますか?

場合によります。

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

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

于 2012-11-25T12:47:03.547 に答える
13

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

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

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

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

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

はい、できますが、質問は「必要があります...」->いいえです。コンテキストは、リクエストごとに使用してリポジトリを変更し、その後再びリポジトリを変更することを目的としています。

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

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

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

4.他のみんなはどうやってこれをやっていますか?

依存性注入によって注入されたDBContext-ファクトリによる注入。スコープ:

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

私の答えが助けになることを願っています。

于 2019-05-17T13:03:43.207 に答える
1

パフォーマンスの観点から、実際に必要なときにDbContext作成justする必要があります。たとえば、ビジネスレイヤー内にユーザーのリストが必要な場合は、DbContextからインスタンスを作成し、immediately dispose作業が完了したときにインスタンスを作成します。

using(var context=new DbContex())
{
var users=context.Users.Where(x=>x.ClassId==4).ToList();

}

contextUsingインスタンスは、ブロックを離れた後に破棄されます。

しかし、すぐに処分しないとどうなるでしょうか。
DbContextは本質的にキャッシュであり、クエリを実行すればするほど、より多くのメモリブロックが占有されます。
アプリケーションにフラッディングが発生した場合は、はるかに目立ちconcurrent requestsます。この場合、メモリブロックを占有しているミリ秒ごとに、1秒は言うまでもなく重要になります。
不要なオブジェクトの破棄を延期すればするほど、アプリケーションは閉じられてクラッシュします。

もちろん、場合によっては、DbContextインスタンスを保持し、コードの別の部分で同じ場所で使用する必要がありますRequest Context

管理に関する詳細については、次のリンクを参照してくださいDbContext。dbcontext
スコープ

于 2021-04-13T14:18:12.023 に答える
0

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

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);
    }
}
于 2015-12-05T21:00:44.397 に答える
0

各Save()操作の直後にコンテキストを破棄する必要があります。そうしないと、後続の各保存に時間がかかります。複雑なデータベースエンティティをサイクルで作成して保存するプロジェクトがありました。驚いたことに、サイクル内で「using(var ctx = new MyContext()){...}」を移動した後、操作が3倍速くなりました。

于 2020-02-26T14:59:16.597 に答える
-1

これは明らかに古い質問ですが、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);
        }
    }
于 2016-07-23T23:26:03.953 に答える