web-dev-qa-db-ja.com

静的クラスでdbcontextを使用する方法は? (ObjectDisposedException)

ちょっと最近、拡張メソッドの使用方法を学び、現在のプロジェクトに実装することにかなり興奮しています。

私の目的:ヘルパークラスのテーブルにエントリが存在するかどうかを確認したいのは、複数のコントローラーでエントリを使用するためです。ナビゲーションバーに表示するナビゲーションリンクを決定できます: enter image description here

私の問題:静的ヘルパークラスのdbcontextにアクセスする方法がわかりません。私のdbcontextコントローラーは、静的クラスを渡す方法がわからない引数を取ります。新しいdbcontextを作成することで、以下で説明するスコープの問題は解決すると思いますが、オプション引数をコンストラクターに渡す方法がわかりません。

enter image description here

現在、Startup.csクラスで構成されています。 enter image description here

私が試したこと:ApplicationDbContextを引数として渡します。これはコントローラーの単一のメソッド呼び出しで機能しますが、複数の拡張メソッドを呼び出すと(ユーザーが持っているゲームアカウントを確認するため)、ObjectDisposedExceptionが発生します。

ObjectDisposedException:破棄されたオブジェクトにアクセスできません。このエラーの一般的な原因は、依存性注入から解決されたコンテキストを破棄し、後でアプリケーションの他の場所で同じコンテキストインスタンスを使用しようとしたことです。これは、コンテキストでDispose()を呼び出す場合、またはコンテキストをusingステートメントでラップする場合に発生する可能性があります。依存性注入を使用している場合は、依存性注入コンテナにコンテキストインスタンスの破棄を任せる必要があります。オブジェクト名: 'ApplicationDbContext'。

私が理解していることから、最初のメソッド呼び出しが完了したときにコンテキストを破棄し、次の呼び出しで同じコンテキストを使用しようとしているのはスコープの問題ですか?それを回避するために何ができますか?

このリンクを読んでみました DbContextを挿入するときにASP.NET Coreで破棄されたオブジェクトにアクセスできません しかし、Startup.csクラスにあるApplicationBuilderが必要なため、役に立ちませんでした。

enter image description here

Solution Updatedbcontextを変数に入れたので、メソッドを呼び出すたびに破棄しました。代わりに、渡されたコンテキストで直接呼び出し、機能します。

enter image description here

7
J.Kirk.

ええ、そうです、拡張機能は新しくて光沢がありますが、それはあなたがそれらをすべてに使うべきだという意味ではありません。まず、拡張機能は、操作しているタイプに論理的に接続されている必要があります。たとえば、stringがある場合、ToUpper()のようなものは、文字列を変更して返すため、拡張子として意味があります。あなたがやろうとしていることのようなもの:参照の値を使用して完全に外部の型を返すだけでは、拡張パターンに違反します。

第二に、拡張機能はデータベースのようなものと相互作用してはなりません。特にここでは、拡張機能の静的な性質は、EFコンテキストオブジェクトの概念と完全に互換性がありません。それを機能させる唯一の方法は、拡張機能が呼び出されるたびに、拡張機能内で実際にコンテキストを新しくすることです。これは、EFオブジェクトトラッキングを台無しにする優れた方法であると同時に、メモリをリークする優れた方法でもあります。

長くも短くも、これをしないでください。

このコードを除外しようとしているだけの場合は、より良いオプションがあります。たとえば、実際にはメソッドをコンテキストに直接追加するだけです。

public class ApplicationDbContext : DbContext
{
    ...

    public bool HasDota2Account(string id)
    {
        return Dota2Accounts.Any(m => m.ApplicationUserId == id);
    }
}

次に、コントローラーで次の操作を実行できます。

var hasDota2Account = context.HasDota2Account(User.Identity.GetUserId());
8
Chris Pratt

DbContextを静的として宣言しないでください。あらゆる種類の問題が発生し、データが更新されないため、クエリから古いデータを取得することになります。オプションは、次のように、使用するたびにstaticメソッド内でインスタンス化することです。

public static MyClass Example
{
        public static bool MyStaticMethod(long id)
        {
            MyDBContext db = new MyDBContext();
            //use db context now....
        }
}
1
live-love

同様の問題が発生し、静的ストレージ(スレッドセーフ)でインスタンス化されたプライベート静的読み取り専用メンバーとしてdbContextを使用することにしました。

public static class PagingHelpers
    {
        private static readonly string _connectionString = ServiceLocator.Current.GetInstance<IConfiguration>().GetConnectionString("DefaultConnection"); // or conn.string
        private static readonly AppDbContext _dbContext=  new AppDbContext(new DbContextOptionsBuilder<AppDbContext>().UseSqlServer(_connectionString).Options);
        private static readonly IDictionary<int, string> departments = _dbContext.Departments.ToDictionary(p => p.DepartmentId, p => p.Name); 
0