web-dev-qa-db-ja.com

Entity Frameworkでリポジトリパターンを使用すべきではないのはなぜですか?

就職の面接中に、リポジトリパターンがEntity FrameworkのようなORMと連携するのに適したパターンではない理由を説明するように求められました。これはなぜですか?

214
StringBuilder

リポジトリパターンがEntity Frameworkで機能しない理由はありません。リポジトリパターンは、データアクセス層に配置する抽象化層です。データアクセスレイヤーは、純粋なADO.NETストアドプロシージャからEntity FrameworkまたはXMLファイルまで何でもかまいません。

さまざまなソース(データベース/ XML/Webサービス)からのデータがある大規模なシステムでは、抽象化レイヤーがあると便利です。このシナリオでは、リポジトリパターンが適切に機能します。 Entity Frameworkは、背後で起こっていることを隠すのに十分な抽象化であるとは思いません。

Entity Frameworkでリポジトリパターンをデータアクセスレイヤーメソッドとして使用しましたが、まだ問題に直面していません。

リポジトリを使用してDbContextを抽象化するもう1つの利点は、単体テスト可能性です。 IRepositoryインターフェースには2つの実装があり、1つ(実際のリポジトリ)はDbContextを使用してデータベースと通信し、もう1つはFakeRepositoryを返すことができます。 -メモリオブジェクト/モックデータ。これにより、IRepositoryの単体テストが可能になるため、IRepositoryを使用するコードの他の部分をテストできます。

public interface IRepository
{
  IEnumerable<CustomerDto> GetCustomers();
}
public EFRepository : IRepository
{
  private YourDbContext db;
  private EFRepository()
  {
    db = new YourDbContext();
  }
  public IEnumerable<CustomerDto> GetCustomers()
  {
    return db.Customers.Select(f=>new CustomerDto { Id=f.Id, Name =f.Name}).ToList();
  }
}
public MockRepository : IRepository
{
  public IEnumerable<CustomerDto> GetCustomers()
  {
    // to do : return a mock list of Customers
    // Or you may even use a mocking framework like Moq
  }
}

今DIを使用して、あなたは実装を取得します

public class SomeService
{
  IRepository repo;
  public SomeService(IRepository repo)
  {
     this.repo = repo;
  }  
  public void SomeMethod()
  {
    //use this.repo as needed
  }    
}
104
Shyju

Entity Frameworkでリポジトリパターンを使用しない唯一の最良の理由は? Entity Framework alreadyはリポジトリパターンを実装します。 DbContextはUoW(作業単位)で、各DbSetはリポジトリです。この上に別のレイヤーを実装すると冗長になるだけでなく、メンテナンスが困難になります。

人々は、パターンの目的を認識せずにパターンに従います。リポジトリパターンの場合、目的は、低レベルのデータベースクエリロジックを抽象化することです。コードでSQLステートメントを実際に作成していた昔、リポジトリパターンは、そのSQLをコードベース全体に散在する個々のメソッドから移動し、1つの場所にローカライズする方法でした。 Entity Framework、NHibernateなどのようなORMを持つことは、このコードの抽象化ではreplacementであり、パターンの必要性を打ち消します。

ただし、ORMの上に抽象化を作成することは悪い考えではなく、UoW/repostitoryほど複雑なものではありません。 Entity Framework、NHibernate、またはWeb APIのいずれからデータが送信されているのかを知らず、気にせずにアプリケーションで使用できるAPIを構築するサービスパターンを使用します。アプリケーションに必要なデータを返すためにサービスクラスにメソッドを追加するだけなので、これははるかに簡単です。たとえば、To-doアプリを作成していた場合、今週の予定でまだ完了していないアイテムを返すサービスコールがあるかもしれません。アプリが知っているのは、この情報が必要な場合はそのメソッドを呼び出すことだけです。そのメソッドの内部とサービス全般では、Entity Frameworkまたはその他の使用しているものとやり取りします。その後、後でORMを切り替えるか、Web APIから情報をプルすることを決定した場合、サービスを変更するだけで、残りのコードは問題なく機能します。

それはリポジトリパターンを使用するための潜在的な議論のように聞こえるかもしれませんが、ここでの主な違いは、サービスがより薄いレイヤーであり、リポジトリ。

452
Chris Pratt

Ayende Rahienからの抜粋を1つ紹介します。 Doomのピットで設計する:リポジトリアブストラクションレイヤーの悪

彼の結論に同意するかどうかはまだわからない。これはキャッチ22です。一方で、EFコンテキストをクエリ固有のデータ取得メソッドでタイプ固有のリポジ​​トリにラップすると、実際にはコード(一種)を単体テストできますが、これはエンティティではほとんど不可能ですフレームワークのみ。一方、関係の豊富なクエリとセマンティックメンテナンスを実行する機能は失われます(ただし、これらの機能に完全にアクセスできる場合でも、EFや他のORMの周りの卵の殻の上を歩いているような気がします、そのIQueryable実装がサポートするメソッドとサポートしないメソッドを知らないので、ナビゲーションプロパティコレクションへの追加を作成として解釈するか、単に関連付けとして解釈するか、遅延ロードか積極ロードか、またはまったくロードしないかデフォルトなどなので、多分これは良いことです。ゼロインピーダンスのオブジェクトリレーショナル「マッピング」は神話上の生き物のようなものです-たぶんそれがEntity Frameworkの最新リリースのコードネームが「マジックユニコーン」であった理由です)。

ただし、クエリ固有のデータ取得メソッドを使用してエンティティを取得すると、ユニットテストは基本的にホワイトボックステストになり、テスト対象のユニットがどのリポジトリメソッドを使用するかを事前に正確に把握する必要があるため、この選択はできません。それをあざけるために呼び出す。また、統合テストも作成しない限り、クエリ自体を実際にテストしているわけではありません。

これらは複雑なソリューションを必要とする複雑な問題です。すべてのエンティティがそれらの間に関係のない別々のタイプであると偽って、それぞれを独自のリポジトリにアトマイズするだけでは修正できません。まああなたはできますが、それは吸います。

更新:Entity Frameworkの Effort プロバイダーを使用して成功しました。 Effortは、実際のデータベースに対してEFを使用する場合とまったく同じように、EFをテストで使用できるようにするインメモリプロバイダー(オープンソース)です。私はこのプロバイダーを使用するために作業しているこのプロジェクトのすべてのテストを切り替えることを検討しています。これは、これまでに見つけた唯一の解決策であり、私が以前に怒っていたすべての問題に対処しています。インメモリデータベースを作成するため、テストを開始するときに若干の遅延がある(唯一これはNMemoryと呼ばれる別のパッケージを使用してこれを行う)だけですが、これは実際の問題とは見なしていません。テストに(SQL CEではなく)Effortを使用することについて説明している Code Project の記事があります。

46
luksan

おそらくそうする理由は、少し冗長であるためです。 Entity Frameworkは、豊富なコーディングと機能上の利点を提供します。そのため、それを使用します。それを利用して、それらの利点を捨てているリポジトリパターンにラップすると、他のデータアクセスレイヤーも使用できるようになります。

16
Nine Tails

理論的には、データベース接続ロジックをカプセル化して再利用しやすくすることは理にかなっていると思いますが、以下のリンクが主張するように、現在のフレームワークは基本的にこれを処理します。

リポジトリパターンの再検討

14
Splendor

非常に良い理由使用するリポジトリパターンは、ビジネスロジックやUIをSystem.Data.Entityから分離できるようにするためです。これには、FakesまたはMocksの使用を許可することによる単体テストでの実際の利点など、数多くの利点があります。

6
James Culshaw

タイプごとにリポジトリをnew()するIoCコンテナー(たとえば、それぞれがDBContextから独自のIDbSetを呼び出すUserRepositoryおよびGroupRepositoryインスタンス)がリクエストごとに複数のコンテキストを引き起こす可能性がある場合、重複するが異なるEntity Framework DbContextインスタンスで問題が発生しました(MVC/Webコンテキスト)。

ほとんどの場合は引き続き機能しますが、その上にサービスレイヤーを追加すると、これらのサービスは、あるコンテキストで作成されたオブジェクトが別のコンテキストの新しいオブジェクトに子コレクションとして正しくアタッチされることを前提とすると、失敗したり、失敗したりすることがありますtコミットの速度によって異なります。

0
Mufasa

小さなプロジェクトでリポジトリパターンを試した後は、使用しないことを強くお勧めします。システムが複雑になるためではなく、データのモックが悪夢であるからではなく、テストが役に立たなくなるためです。

データのモックを使用すると、ヘッダーなしで詳細を追加したり、データベースの制約に違反するレコードを追加したり、データベースが削除を拒否するエンティティを削除したりできます。現実の世界では、1つの更新が複数のテーブル、ログ、履歴、要約などのほか、最終更新日フィールド、自動生成キー、計算フィールドなどの列に影響を与える可能性があります。

つまり、実際のデータベースでテストを実行すると実際の結果が得られ、サービスとインターフェースだけでなくデータベースの動作もテストできます。ストアドプロシージャがデータを使用して適切な処理を行っているか、期待どおりの結果が返されているか、削除するために送信したレコードが本当に削除されているかを確認できます。このようなテストは、ストアドプロシージャからのエラーの発生を忘れるなどの問題や、このようなシナリオの数千も公開する可能性があります。

エンティティフレームワークは、これまでに読んだどの記事よりも優れたリポジトリパターンを実装しており、彼らが達成しようとしているものをはるかに超えています。

リポジトリは、XBase、AdoX、およびAdo.Netを使用していた当時はベストプラクティスでしたが、エンティティを使用していました。 (リポジトリよりリポジトリ)

最後に、リポジトリパターンの学習と実装に多くの時間を費やしている人が多すぎて、手放すことを拒否していると思います。主に、時間を無駄にしていないことを証明するためです。

0
Zawer Haroon