web-dev-qa-db-ja.com

リポジトリパターンの回避-DbContextのみでOnionアーキテクチャを実装する

Onion Architecture に従って、次のレイヤーがあるアプリケーションを設計しようとしています-

  • ドメイン層:最も内側の層であり、リポジトリインターフェースを定義します
  • インフラストラクチャ層:Web/UI層とピアリングされた最も外側の層を形成し、リポジトリインターフェースを実装します
  • サービス層:ビジネスロジックが存在し、リポジトリインターフェースが挿入される中間層です
  • Web/UIレイヤー:インフラストラクチャレイヤーとピアリングされた最も外側のレイヤーを形成し、DI構成を処理します

物事は機能しています。これまでのところ問題はありません。

DbContext自体が実装され、各IDbSet<T>がリポジトリ。私はそのポイントを理解しています。それはとても良いことです。なぜなら、書くコードが少ないからです。それで、リポジトリを避けてDbContextのみを使用してアプリケーションを構造化する方法を見つけることができるかどうか見てみようと思いました。

私が見つけたいくつかの推奨事項は、コントローラーでDbContextを直接使用することを提案していますが、これは好ましくありませんでした。コントローラーコードがクエリで煩雑になりたくありません。私はそれらをスリムにし、現在サービスクラスで行っているように、ビジネス処理とデータベース操作を誰かに委任します。

私はこの記事を読みました Ditch the Repository Pattern Already とコメントセクションで、1つのコメントへの応答として、作者はオニオンアーキテクチャを使用しており、-

アプリケーション層が個別の層として存在する場合は、DbContextとおそらく他の依存関係が注入されます。 Webアプリケーションの場合、UIレイヤーはすべてのDIをセットアップし、要求をアプリケーションレイヤーへの呼び出しに変換し、ブラウザーに送信される応答をビューモデルにマップします。持続性レイヤーなどの他のインフラストラクチャレイヤーでは、UIレイヤーを「ピア」レイヤーとして、外側のレイヤーにDbContextを定義しています。

Onion Architectureによると、依存関係は内側にのみ進むべきなので、私が本当に理解していないのは、DIを介してアプリケーションレイヤーでDbContext(インフラストラクチャレイヤーで定義)の参照を取得する方法です。

EF/EF Coreでリポジトリおよび作業ユニットパターンを実装しないことを好む人のために、オニオンアーキテクチャを使用して同じようにしてアプリケーションを構築する方法を提案できますか?

編集-2020年2月3日

Flater に感謝します。私は誰もが提供したすべてのリンクを通過しました。ありがとうございます。

しかし、問題を適切に表現できなかったようです。もう一度やってみます。私のアプリケーションは、次のOnion Architectureの図で表すことができます-

Onion Architecture with no Application Layer

各レイヤーは、便宜上、個別のプロジェクトとして実装されます。 Onion Architectureは依存関係がonly内向きになることを指示しているため-

Domain-他のプロジェクトに依存していません。モデルとインターフェースを定義します。

Service-ドメインのみに依存します。 Serviceインターフェースを実装するServiceクラスが含まれます。サービスクラスには、リポジトリインターフェイスが挿入されます。

インフラストラクチャ-ドメインに依存しています。 DbContextを定義します。これには、Repositoryインターフェースを実装するRepositoryクラスが含まれています。リポジトリクラスにはDbContextが挿入されます。

Web/UI-サービスとドメインに依存しています。これには、サービスインターフェイスまたはリポジトリインターフェイス、あるいはその両方が注入されたコントローラクラスが含まれています。 (このプロジェクトはインフラストラクチャーにも依存していますが、これはDI構成のみを目的としています)。

Onion Architectureは、インフラストラクチャの一部として最外部のレイヤーに永続化操作を配置し、依存関係の反転を使用してそれらにアクセスします。これにより、アプリケーションコア(アプリケーション+サービス+ドメインレイヤーで構成される)がデータアクセスレイヤー/テクノロジーに依存しない疎結合設計になります。

私が言ったとき-

私が本当に理解していないのは、DIを介してアプリケーション層のDbContext(インフラストラクチャ層で定義)の参照を取得する方法です。

つまり、リポジトリを破棄してDbContextのみを使用する場合、サービスクラスのDbContextを使用する必要がありますが、DbContextはインフラストラクチャで定義されており、サービスにはインフラストラクチャへの参照がありません。

DbContext、サービスレイヤーを使用するには、インフラストラクチャへの直接参照が必要です。この参照を追加すると、Onion Architectureが必要とする最も基本的な概念に違反します。依存関係は常に内側に向かう必要があります。この要件により、DIPを使用して外部への依存を解決し、疎結合を実現する必要があります。

したがって、サービスレイヤーがインフラストラクチャへの参照を持っている場合、アプリケーションコアはデータアクセスレイヤーに直接依存しており、もうOnionと呼ぶことはできないと思います。

それが私の質問が来る場所です-どのようにしてリポジトリを回避し、DbContextのみを使用し、それでもOnion Architectureを守ることができますか?

小さなアプリケーションで使用できるものを実装しようとしているだけです。Repo/ UoWアプローチは、一部のシナリオでは過剰であり、さらに多くのコードを記述する必要がないためです。

5
atiyar

リポジトリを使用するための核となる議論は、EFに依存するコードがドメインにリークするのを防ぐことです。その議論は間違いではありません、それは高額なコスト、つまり複雑さを増したuow/repoレイヤーを伴うだけであり、それは現在、(少なくとも、いくつかによって)それが与えるものを支払うには高すぎる価格と見なされています。

そのuow/repoレイヤーを使用しないことで、ドメインを実際にEF(コンテキストとデータベースセット)に依存させることができます。それだけはやむを得ない。

私は EFを使用したリポジトリでの長い回答 を書いたことがあります。私の反リポジトリの結論を要約すると、これがエンティティライブラリではなくエンティティFrameworkと呼ばれる理由です。フレームワークは、フレームワークの構造全体を効果的に複製する必要がない限り、合理的に抽象化できないものです(これにより、フレームワークを使用することの利点が失われます)。

私が本当に理解していないのは、DIを介してアプリケーションレイヤーでDbContext(インフラストラクチャレイヤーで定義)の参照を取得する方法です。

本質的には、UOW /リポジトリレイヤーを実装した場合に、自分で作成したUOWへの参照を取得する方法と同じです。 DBコンテキストをDIフレームワークに登録すると、サービスレイヤーでこのコンテキストを挿入できます。

これが私のプロジェクトの1つからの.Net Coreの例です。

services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connString));

直接dbコンテキストクラスではなくインターフェイスを使用することは可能ですが、それが必要になったプロジェクトについては、実際には扱っていません。必要に応じて使用してください。

この登録は最上位のプロジェクトに存在する必要がないことに注意してください(タマネギのレイヤー化に違反するため)。私は実際にこの永続化プロジェクトでこの登録を行います。以下に沿ったもの:

// In Persistence

public static class DependencyRegistration
{
    public static void Register(IServiceCollection services, string connString)
    {
        services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connString));
    }
}

// In top-level Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    Persistence.DependencyRegistration.Register(services, "myConnString");
}

このようにして、最上位プロジェクトは実際にはEF dllに依存する必要はありません(EFから何も参照しないため)が、それでも(独自の構成から)接続文字列を決定する権限があり、必要なEF関連のDI登録をセットアップするように永続層に指示します。

注:純粋なオニオンアーキテクチャの場合、最上位のプロジェクトは、その依存関係を登録するよう永続性に指示するべきではありません。むしろ、トップレイヤープロジェクトはサービス/アプリケーションレイヤーに登録を行うように指示し、サービス/アプリケーションレイヤーは永続性レイヤーにそれらの登録を行うよう指示します。
私の例は完全なタマネギではありませんが、簡単にするためにそれを保持しました。レイヤーごとにコールチェーンを設定するのは簡単ですが、私の例を不必要に長くすることになります。

持続性レイヤーなどの他のインフラストラクチャレイヤーでは、UIレイヤーを「ピア」レイヤーとして、外側のレイヤーにDbContextを定義しています。

ここで彼らが何を意味するのか本当にわかりません。この永続性とUIが「ピアレイヤー」であるというこの説明は、実際のオニオンアーキテクチャがどうあるべきかと矛盾しているように聞こえます。


より大きな例については、 NorthwindTraders githubリポジトリを確認してください。このレポの作者は Youtubeでのプレゼンテーション もあり、その方法(および理由)について詳しく説明しています。

4
Flater