8

私は Linq to Entities を使用していますが、最近、多くの人が次のような using ステートメントで datacontext をラップすることを推奨していることに気付きました。

Using(DataContext db = new DataContext) {
    var xx = db.customers;
}

意味あり。ただし、このプラクティスをモデルに組み込む方法がわかりません。例:私はインターフェース(顧客と呼びましょう)を持っており、次のようなリポジトリによって実装されています:

namespace Models
{
    public class rCustomer : iCustomer
    {

        readonly DataContext db = new DataContext();

        public customer getCustomer(Guid id)
        {
            return db.customers.SingleOrDefault(por => por.id == id);
        }

        public iQueryable<customer> getTopCustomers()
        {
            return db.customers.Take(10);
        }

        //*******************************************
        //more methods using db, including add, update, delete, etc.
        //*******************************************

    }
}

次に、使用を利用するには、メソッドを次のように変更する必要があります。

namespace Models
{
    public class rCustomer : iCustomer
    {
        public customer getCustomer(Guid id)
        {
            using(DataContext db = new DataContext()) {       
                return db.customers.SingleOrDefault(por => por.id == id);
            } 
        }

        public iQueryable<customer> getTopCustomers()
        {
            using(DataContext db = new DataContext()) {       
                 return db.customers.Take(10);
            } 
        }

        //*******************************************
        //more methods using db
        //*******************************************

    }
}

私の質問は、「Using」を使用することの推奨は本当に良いですか? この変更は大きなものになることを考慮してください。約 25 のインターフェイス/リポジトリ コンボがあり、それぞれに約 20 ~ 25 のメソッドがあり、完了後にすべてを再テストする必要があることは言うまでもありません。他の方法はありますか?

ありがとう!

エドガー。

4

5 に答える 5

5

DbContext を再利用するデータベース ファクトリを実装できます。

これは次のようにして実現できます。

DatabaseFactory クラス:

public class DatabaseFactory : Disposable, IDatabaseFactory
{
    private YourEntities _dataContext;
    public YourEntities Get()
    {
        return _dataContext ?? (_dataContext = new YourEntities());
    }
    protected override void DisposeCore()
    {
        if (_dataContext != null)
            _dataContext.Dispose();
    }
}

リポジトリ基本クラスの抜粋:

 public abstract class Repository<T> : IRepository<T> where T : class
{
    private YourEntities _dataContext;
    private readonly IDbSet<T> _dbset;
    protected Repository(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        _dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get;
        private set;
    }

    protected YourEntities DataContext
    {
        get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
    }

テーブルのリポジトリ クラス:

public class ApplicationRepository : Repository<YourTable>, IYourTableRepository
{
    private YourEntities _dataContext;

    protected new IDatabaseFactory DatabaseFactory
    {
        get;
        private set;
    }

    public YourTableRepository(IDatabaseFactory databaseFactory)
        : base(databaseFactory)
    {
        DatabaseFactory = databaseFactory;
    }

    protected new YourEntities DataContext
    {
        get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
    }

   }
    public interface IYourTableRepository : IRepository<YourTable>
   {
   }
}

これは、AutoFac コンストラクター インジェクションとも完全に連携します。

于 2012-04-23T14:03:18.730 に答える
3

提供されたコードを考えると、明示readonly DataContext db = new DataContext();的にグローバル変数のように使用するため、そのオブジェクトの有効期間とrCustomerクラス インスタンスの有効期間を考慮する必要があります。

これが本当なら、あなたができることは、すべてを書き直す代わりに、次のようなコードを実装IDisposableして内部に置くことができますDispose()

private void Dispose()
{
    if(db  != null) 
        db.Dispose();
}

お役に立てれば。

于 2012-04-23T14:06:44.500 に答える
3

他の人が述べたように、データ コンテキストを破棄することが重要です。これ以上は触れません。

コンテキストが破棄されることを保証するクラスの設計として、次の 3 つが考えられます。

  1. 提供する 2 番目のソリューションでは、各メソッドのスコープ内でデータ コンテキストを作成し、各データ コンテキストがブロックrCustomer内にあるようにする必要があります。using
  2. データ コンテキストをインスタンス変数として保持し、rCustomerIDisposable を実装して、rCustomerが破棄されたときにそのデータ コンテキストを破棄できるようにします。これは、すべてのインスタンスをブロックrCustomerでラップする必要があることを意味します。using
  3. rCustomerコンストラクターを介して、既存のデータ コンテキストのインスタンスを渡します。これを行うrCustomerと、それを破棄する責任はありません。クラスのユーザーが責任を負います。これにより、単一のデータ コンテキストを の複数のインスタンスで使用しrCustomerたり、データ コンテキストにアクセスする必要がある複数の異なるクラスで使用したりできます。これには、利点 (新しいデータ コンテキストの作成に伴うオーバーヘッドが少ない) と欠点 (データ コンテキストがキャッシュなどを通じて大量のメモリを保持する傾向があるため、メモリ フットプリントが大きい) があります。

正直なところ、オプション#1は、パフォーマンスが遅すぎることに気付かない限り、かなり良いものだと思います(問題が発生していると思われる場合は、時間とプロファイルを作成します)。接続プーリングのため、それほど悪くはありません。もしそうなら、私は次の選択肢として#3を選びます。#2はそれほど遅れていませんが、チームの他のメンバー(いる場合)にとっては少しぎこちなく、予期しないものになる可能性があります.

于 2012-04-23T14:24:49.540 に答える
2

DataContext クラスは IDisposable インターフェイスを実装するため、Using ステートメントでラップされます。

DataContext の内部では、SqlConnection オブジェクトと SqlCommand オブジェクトを使用しています。これらの接続を SQL 接続プールに正しく解放するには、破棄する必要があります。

最終的にはガベージ コレクターがこれを行いますが、IDisposable オブジェクトの管理方法により、2 回のパスが必要になります。

Dispose を呼び出すことを強くお勧めします。Using ステートメントは、これを行うための優れた方法です。

詳細な説明については、次のリンクを参照してください。

http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe/

http://www.c-sharpcorner.com/UploadFile/DipalChoksi/UnderstandingGarbageCollectioninNETFramework11292005051110AM/UnderstandingGarbageCollectioninNETFramework.aspx

于 2012-04-23T14:06:16.283 に答える
2

別の方法として、rCustomer クラスにIDisposableを実装し、Disposeメソッドで、DataContext が null でない場合は Dispose を呼び出すことができます。ただし、これは Disposable パターンを rCustomer クラスから、rCustomer を使用している型にプッシュするだけです。

于 2012-04-23T14:08:13.410 に答える