1

複数のリポジトリ間で 4 つの DbSet を持つ単純な DbContext を共有しようとしています。各リポジトリはこの基本クラスから継承しています

 public class CodeFirstRepository : IDisposable
    {
        private static MyContext _ctx = new MyContext();
        protected MyContext Context
        {
            get { return _ctx; }
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
            }
        }
    }

質問: これはリポジトリ間の接続を共有する適切な方法ですか?

さまざまなリポジトリにアクセスすると、単体テストで断続的なエラーが発生します。リポジトリ メソッド GetEntityByName から例外がスローされる

public IOfferResult GetEntityByName(string name)
{
   return Context.Entities.Where(o => o.Name == name).FirstOrDefault()
}

テスト メソッド Tests.Service.TestDelete が例外をスローしました: System.ObjectDisposedException: ObjectContext インスタンスが破棄されたため、接続を必要とする操作には使用できなくなりました。

データベースが既に存在する場合、コードは期待どおりに実行されます。GetEntityByName(string name) の実装を次の非パフォーマンス コードに変更した場合にも機能します

public IOfferResult GetEntityByName(string name)
{
   foreach (OfferResult offer in Context.Offers)
   {
       if (offerName.ToLower() == offer.Name.ToLower())
       {
           return offer;
       }
   }
}

質問: ここで何が起こっているのですか?

テストを実行したときにデータベースが存在する場合、エラーはまったく発生しないことに注意してください。

ティア、jt

4

1 に答える 1

3

この問題はDbContext、フィールドとして宣言してシングルトンのように扱っているために発生していますが、のインスタンスが破棄されるとすぐに破棄することで、一時的staticインスタンスのように扱っています。例えば:CodeFirstRepository

using (var r = new PersonRepository())
{
   // do something
} // When you hit the end of this block, your static DbContext is disposed.
using (var r = new IOfferRepository())
{
    r.GetEntityByName("test"); // this will fail because the context is still disposed.
}

この方法でコンテキストを共有しないでください。すべてのリポジトリで の 1 つのインスタンスを本当に使用したい場合は、DbContextへの呼び出しを削除しますContext.Dispose()。これにより、現在発生している問題は修正されますが、将来的には他の問題が発生する可能性があります。

DbContextただし、複数のスレッドが同時にアクセスしようとする可能性があるシナリオでは、シングルを使用しないように強く注意します。DbContext 仕様によると:

インスタンス メンバーは、スレッド セーフであるとは限りません。

staticフィールドからキーワードを削除した方がよいでしょう。

于 2011-10-04T17:46:49.500 に答える