リポジトリとサービス層の違いは?


188

OOP設計パターンで、リポジトリパターンとサービスレイヤーの違いは何ですか?

私はASP.NET MVC 3アプリに取り組んでおり、これらのデザインパターンを理解しようとしていますが、私の脳はまだ理解していません...まだです!!

回答:


327

リポジトリ層は、データアクセスに対する追加レベルの抽象化を提供します。書く代わりに

var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();

データベースから単一のアイテムを取得するには、リポジトリインターフェイスを使用します

public interface IRepository<T>
{
    IQueryable<T> List();
    bool Create(T item);
    bool Delete(int id);
    T Get(int id);
    bool SaveChanges();
}

そしてを呼び出しますGet(id)。リポジトリ層は、基本的なCRUD操作を公開します。

サービス層は、リポジトリを使用するビジネスロジックを公開します。サービスの例は次のようになります。

public interface IUserService
{
    User GetByUserName(string userName);
    string GetUserNameByEmail(string email);
    bool EditBasicUserData(User user);
    User GetUserByID(int id);
    bool DeleteUser(int id);
    IQueryable<User> ListUsers();
    bool ChangePassword(string userName, string newPassword);
    bool SendPasswordReminder(string userName);
    bool RegisterNewUser(RegisterNewUserModel model);
}

一方でList()、すべてのユーザーが、リポジトリリターンの方法ListUsers()IUserServiceのが唯一のものを返すことができ、ユーザーはへのアクセス権を持っています。

ASP.NET MVC + EF + SQL SERVERでは、次の通信フローがあります。

ビュー<-コントローラー->サービスレイヤー->リポジトリレイヤー-> EF-> SQL Server

サービス層->リポジトリ層-> EFこの部分はモデルで動作します。

ビュー<-コントローラ->サービス層このパーツはビューモデルで動作します。

編集:

/ Orders / ByClient / 5のフローの例(特定のクライアントの注文を確認したい):

public class OrderController
{
    private IOrderService _orderService;

    public OrderController(IOrderService orderService)
    {
        _orderService = orderService; // injected by IOC container
    }

    public ActionResult ByClient(int id)
    {
        var model = _orderService.GetByClient(id);
        return View(model); 
    }
}

これは注文サービスのインターフェースです:

public interface IOrderService
{
    OrdersByClientViewModel GetByClient(int id);
}

このインターフェースはビューモデルを返します。

public class OrdersByClientViewModel
{
     CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
     IEnumerable<OrderViewModel> Orders { get; set; }
}

これはインターフェースの実装です。モデルクラスとリポジトリを使用してビューモデルを作成します。

public class OrderService : IOrderService
{
     IRepository<Client> _clientRepository;
     public OrderService(IRepository<Client> clientRepository)
     {
         _clientRepository = clientRepository; //injected
     }

     public OrdersByClientViewModel GetByClient(int id)
     {
         return _clientRepository.Get(id).Select(c => 
             new OrdersByClientViewModel 
             {
                 Cient = new ClientViewModel { ...init with values from c...}
                 Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}     
             }
         );
     }
}

2
@Sam Striano:上記のように、私のIRepositoryはIQueryableを返します。これにより、追加のwhere条件を追加して、後でではなくサービスレイヤーで実行を延期できます。はい、1つのアセンブリを使用していますが、これらのクラスはすべて異なる名前空間に配置されています。小さなプロジェクトで多くのアセンブリを作成する理由はありません。名前空間とフォルダの分離はうまく機能します。
LukLed

81
サービスでビューモデルを返す理由 複数のクライアント(モバイル/ Web)がある場合、サービスはエミュレートすると想定されていませんか?その場合、viewmodelは異なるプラットフォームと異なる場合があります
Ryan

12
@Ryanに同意すると、サービスレイヤーはエンティティオブジェクトまたはエンティティオブジェクトのコレクションを返す必要があります(IQueryableではありません)。次に、UIエンティティは、たとえばAutomapperによってSomeViewModelにマップされます。
Eldar

5
@Duffp:エンティティごとにリポジトリを作成する必要はありません。汎用的な実装を使用IRepository<>GenericRepository<>て、IOCライブラリにバインドできます。この答えは非常に古いです。最善の解決策は、すべてのリポジトリをと呼ばれる1つのクラスに結合することですUnitOfWork。すべてのタイプのリポジトリとと呼ばれる1つのメソッドが含まれている必要がありますSaveChanges。すべてのリポジトリは1つのEFコンテキストを共有する必要があります。
LukLed 2013

2
サービスレイヤーからviewmodelを返す代わりに、DTOを返し、automapperを使用してそれをviewModelsに変換する必要があります。それらが同じでない場合は、YGTNIを実装したことに感謝します "You're Going Toそれを必要とする」
ハンゾロ2014年

41

Carnotaurusが言ったように、リポジトリはデータをストレージフォーマットからビジネスオブジェクトにマッピングする責任があります。ストレージとの間のデータの読み取りと書き込み(削除、更新も)の両方を処理する必要があります。

一方、サービス層の目的は、ビジネスロジックを単一の場所にカプセル化して、コードの再利用と問題の分離を促進することです。Asp.net MVCサイトを構築するとき、これが実際に私にとって通常意味することは、私がこの構造を持っているということです

[Controller]が[Service(s)]を呼び出し、[Repository(ies)]を呼び出す

私が有用であるとわかった1つの原則は、コントローラーとリポジトリーでロジックを最小限に抑えることです。

コントローラーでそれは私を乾燥した状態に保つのを助けるからです。同じフィルタリングまたはロジックを他の場所で使用する必要があることは非常に一般的であり、コントローラーに配置した場合、再利用できません。

リポジトリでは、何か良いものが来たときにストレージ(またはORM)を交換できるようにしたいからです。リポジトリにロジックがある場合、リポジトリを変更するときにこのロジックを書き換える必要があります。一方、リポジトリがIQueryableのみを返し、サービスがフィルタリングを行う場合、マッピングを置き換えるだけで済みます。

たとえば、私は最近、Linq-To-SqlリポジトリのいくつかをEF4に置き換えました。この原則に忠実であったリポジトリは、ほんの数分で置き換えられる可能性があります。私が何らかの論理を持っているところでは、代わりに数時間の問題でした。


私はミカエルに同意します。実際、私は私のテクノロジーブログfreecodebase.comで同じシナリオを適用し、この実装ではコードファーストアプローチを使用しました。ソースコードもここからダウンロードできます。
タフィー

私は既存のMVCアプリにリポジトリパターンを適用する一般的なテーマを調査しています。これは、Active Recordに似たORMとその他のRails / Laravelの規約を使用したオーダーメイドのフレームワークであり、現在行っている作業にはいくつかのアーキテクチャ上の問題があります。私が遭遇したことの1つは、リポジトリが「ViewModels、DTO、またはクエリオブジェクトを返すべきではない」ということですが、リポジトリオブジェクトを返すべきです。などのメソッドを介してサービスがリポジトリオブジェクトとやり取りしonBeforeBuildBrowseQuery、クエリビルダーを使用してクエリを変更できる場所を考えています。
calligraphic-io

@Toffee、リンクが壊れています。更新してください。この実装のソースコードが必要です。
Hamza Khanzada

24

受け入れられた回答(そして何百回も賛成)には大きな欠陥があります。私はコメントでこれを指摘したかったのですが、30のコメントで埋められるので、ここで指摘します。

そのように構築されたエンタープライズアプリケーションを引き継ぎ、私の最初の反応はWTHでしたか?サービスレイヤーのViewModels?何年も開発が進んでいたため、私は規約を変更したくなかったので、ViewModelsを返し続けました。WPFを使い始めたとき、それは悪夢に変わりました。私たち(開発チーム)はいつも言っていました:どのViewModelですか?実際のもの(WPF用に作成したもの)またはサービスのもの これらはWebアプリケーション用に作成され、UIでの編集を無効にするためのIsReadOnlyフラグさえありました。メジャー、メジャーな欠陥、そしてすべて1つの単語:ViewModel !!

同じ間違いをする前に、上記の私の話に加えて、いくつかの理由があります。

サービスレイヤーからViewModelを返すのは非常に困難です。それは言っているようなものです:

  1. これらのサービスを使用する場合は、MVVMを使用することをお勧めします。ここに、使用する必要のあるViewModelを示します。痛い!

  2. サービスは、UIのどこかに表示されることを想定しています。WebサービスやWindowsサービスなどの非UIアプリケーションで使用されている場合はどうなりますか?

  3. これは実際のViewModelでもありません。実際のViewModelには可観測性、コマンドなどがあります。これは、悪い名前のPOCOです。(名前が重要な理由については、上の私のストーリーを参照してください。)

  4. 使用するアプリケーションはプレゼンテーションレイヤー(ViewModelはこのレイヤーで使用されます)であり、C#をよく理解しています。別の痛い!

しないでください!


3
「これは悪い名前のPOCOにすぎません」とディスカッションに追加されないことはわかっていますが、これについてコメントしなければなりませんでした。<<-それはTシャツに似合うでしょう!:) :)
Mephisztoe

8

通常、リポジトリは、エンティティを設定するための足場として使用されます。サービスレイヤーは外に出て、リクエストをソースします。サービスレイヤーの下にリポジトリを配置する可能性があります。


したがって、EF4を使用するASP.NET MVCアプリでは、次のようになります。SQLServer-> EF4->リポジトリ->サービスレイヤー->モデル->コントローラー、およびその逆?
サム

1
ええ、リポジトリを使用してEF4から軽量エンティティを取得できます。サービスレイヤーを使用して、これらを専用のモデルマネージャー(シナリオのモデル)に送り返すことができます。これを行うには、コントローラーが専門のモデルマネージャーを呼び出します... Mvc 2/3の私のブログをざっと見てください。私は図を持っています。
CarneyCode、2011

明確にするために:シナリオのEF4は、モデルがダイアグラムにあり、シナリオのモデルは、ダイアグラムの専門のモデルマネージャーです
CarneyCode

4

リポジトリ層は、データベースにアクセスするために実装され、データベースでのCRUD操作の拡張に役立ちます。一方、サービス層はアプリケーションのビジネスロジックで構成され、リポジトリ層を使用して、データベースに関連する特定のロジックを実装できます。アプリケーションでは、リポジトリレイヤーとサービスレイヤーを分離することをお勧めします。別個のリポジトリー層とサービス層を使用すると、コードがよりモジュール化され、データベースがビジネスロジックから切り離されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.