コントローラがサービスの代わりにリポジトリを呼び出すのは悪い習慣ですか?
さらに説明する:
優れた設計では、コントローラーがサービスを呼び出し、サービスがリポジトリを使用することがわかります。
ただし、コントローラーにはロジックがない場合や必要ない場合があり、dbからフェッチしてビューに渡すだけでよい場合があります。
そして、私はリポジトリを呼び出すだけでそれを行うことができます-サービスを呼び出す必要はありません-それは悪い習慣ですか?
コントローラがサービスの代わりにリポジトリを呼び出すのは悪い習慣ですか?
さらに説明する:
優れた設計では、コントローラーがサービスを呼び出し、サービスがリポジトリを使用することがわかります。
ただし、コントローラーにはロジックがない場合や必要ない場合があり、dbからフェッチしてビューに渡すだけでよい場合があります。
そして、私はリポジトリを呼び出すだけでそれを行うことができます-サービスを呼び出す必要はありません-それは悪い習慣ですか?
回答:
いいえ、このように考えてください:リポジトリは(また)サービスです。
リポジトリから取得したエンティティがほとんどのビジネスロジックを処理する場合、他のサービスは必要ありません。リポジトリがあれば十分です。
エンティティを操作するためにパススルーする必要があるサービスがある場合でも。最初にリポジトリからエンティティを取得してから、そのサービスに渡します。試みる前にHTTP 404を投げることができるのは非常に便利です。
また、読み取りシナリオの場合、エンティティをDTO / ViewModelに投影する必要があるのが一般的です。その間にサービスレイヤーを配置すると、多くの場合パススルーメソッドがかなりlotいものになります。
コントローラがリポジトリを直接呼び出すことは悪い習慣ではありません。「サービス」は単なるツールであるため、意味のある場所で使用してください。
NikolaiDanteはコメントしました:
...適切なアプリケーションに適切なパターンを選択します。私が言うことは、アプリケーションの一貫性を保つ必要があるということです。
一貫性が最も重要な側面だとは思いません。「サービス」クラスは、コントローラがそれを実装する必要がないように、より高いレベルのロジックをカプセル化することを目的としています。特定の操作に「上位レベルのロジック」が必要ない場合は、リポジトリに直接移動してください。
適切な懸念とテスト容易性を促進するために、リポジトリはコンストラクタを介してサービスに注入する依存関係である必要があります。
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
データベース内のレコードの検索に何らかのパラメータ化されたクエリが必要な場合、サービスクラスはビューモデルを取得し、リポジトリによって実行されるクエリを構築するのに適した場所になる可能性があります。
同様に、フォームに複雑なビューモデルがある場合、サービスクラスは、ドメインモデル/エンティティのメソッドを呼び出し、リポジトリを使用してそれらを永続化することにより、レコードの作成、更新、削除のロジックをカプセル化できます。
コントローラがそのIDでレコードを取得する必要がある場合、反対方向に進むと、このためにサービスオブジェクトに委任することは、ハンマーで画thumbを打つようなものです-それは必要以上の方法です。
コントローラがトランザクションまたは作業単位オブジェクトを処理するのに最適な位置にあることがわかりました。コントローラーまたは作業単位オブジェクトは、複雑な操作の場合はサービスオブジェクトに委任するか、単純な操作の場合はリポジトリに直接移動します(IDによるレコードの検索など)。
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
サービスを組み合わせてリポジトリを直接操作することは完全に受け入れられると思います。必要に応じて、トランザクションを作業単位オブジェクトにさらにカプセル化できます。
責任の内訳は次のようになります。
DbContext
この場合、悪い名前だと思います。それを変更します。私はNHibernateを使用し、リポジトリ(または便利な場合はコンテキスト)がデータベースの終わりを管理するため、永続化メカニズムを変更しても、コンテキスト外でコードを変更する必要はありません。
それはあなたのアーキテクチャに依存します。私はSpringを使用しており、トランザクション性は常にサービスによって管理されています。
書き込み操作(または単にリポジトリに委任するロジックのない単純なサービス)のためにリポジトリを直接呼び出す場合、1つの操作で実行する必要がある操作に複数のデータベーストランザクションを使用している可能性があります。それはあなたのデータベースに一貫性のないデータをもたらすでしょう。一般的なルールとして、データベース操作は機能するか、または失敗するはずですが、半分動作する操作が頭痛の原因です。
そのため、コントローラーからリポジトリーを直接呼び出したり、単純な委任サービスを使用したりするのは悪い習慣だと思います。あなたはただ読むためにそれを始め、すぐにあなた、またはあなたの仲間が書き込み操作のためにそれを始めます。