コントローラがサービスの代わりにリポジトリを呼び出すのは悪い習慣ですか?
詳細を説明するには:
良い設計では、コントローラーはサービスとサービス使用リポジトリを呼び出します。
ただし、コントローラーでは、ロジックを必要としない場合があり、dbからフェッチしてそれを表示に渡す必要があるだけです。
そして、私はリポジトリを呼び出すだけでそれを行うことができます-サービスを呼び出す必要はありません-それは悪い習慣ですか?
いいえ、このように考えてください:リポジトリis aサービス(また)。
リポジトリを介して取得するエンティティがビジネスロジックのほとんどを処理する場合、他のサービスは必要ありません。リポジトリがあれば十分です。
エンティティを操作するために通過する必要があるサービスがある場合でも、最初にリポジトリからエンティティを取得してから、それを上記のサービスに渡します。試行する前にHTTP 404を放棄できることは非常に便利です。
また、読み取りシナリオでは、DTO/ViewModelに投影するエンティティが必要なのが一般的です。その間にサービスレイヤーがあると、多くの場合、パススルーメソッドが多くなり、見苦しくなります。
コントローラがリポジトリを直接呼び出すことは悪い習慣ではありません。 「サービス」は単なる別のツールであるため、意味のある場所で使用してください。
NikolaiDanteがコメントしました:
...適切なアプリケーションに適したパターンを選択してください。私が言うことは、アプリケーションを一貫させる必要があるということです。
一貫性が最も重要な側面だとは思いません。 「サービス」クラスは、コントローラがそれを実装する必要がないように、いくつかの高レベルのロジックをカプセル化することを意図しています。特定の操作に「高レベルのロジック」が必要ない場合は、リポジトリに直接移動してください。
懸念の分離とテスト容易性を促進するには、リポジトリを、コンストラクタを介してサービスに注入する依存関係にする必要があります。
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
データベース内のレコードを検索するために何らかのパラメーター化されたクエリが必要な場合、サービスクラスはビューモデルを取得して、リポジトリによって実行されるクエリを構築するのに適した場所です。
同様に、フォームの複雑なビューモデルがある場合、サービスクラスは、ドメインモデル/エンティティのメソッドを呼び出してレコードを作成、更新、削除するロジックをカプセル化し、リポジトリを使用してそれらを永続化できます。
コントローラーがIDでレコードを取得する必要がある場合は、反対方向に進み、サービスオブジェクトに委任することは、大ハンマーで画鋲を打つようなものです-必要以上のことです。
コントローラーがトランザクションを処理するのに最適な位置にあること、または 作業単位オブジェクト であることがわかりました。次に、コントローラーまたは作業単位オブジェクトは、複雑な操作の場合はサービスオブジェクトに委任するか、単純な操作(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);
}
}
}
}
サービスの組み合わせとリポジトリの直接操作は完全に許容できると思います。必要に応じて、トランザクションを作業単位オブジェクトにさらにカプセル化できます。
責任の内訳は次のようになります。
それはあなたのアーキテクチャに依存します。私はSpringを使用しており、トランザクション性は常にサービスによって管理されています。
書き込み操作(または単にリポジトリに委任するロジックのない単純なサービス)のためにリポジトリを直接呼び出す場合は、1つの操作で複数のデータベーストランザクションを実行する必要があります。それはあなたのデータベースの矛盾したデータにつながります。原則として、データベース操作は機能するか、失敗するはずですが、半機能の操作は頭痛の原因です。
そのため、コントローラから直接リポジトリを呼び出すことや、単純な委任サービスを使用することは悪い習慣だと思います。あなたは読み取りのためだけにそれを始めます、そしてすぐにあなた、あるいはあなたの仲間は書き込み操作のためにそれを始めます。
はい、それは悪い習慣です。コントローラは、アプリケーションのフローを制御し、クライアントアプリから入力を取得し、サービスを呼び出し、データをビュー(JSON/HTML/XML/etc)に渡すためにのみ使用する必要があります。リポジトリ/ DAOは、ビジネスロジックを知らなくてもデータを取得/保持するために使用する必要があります。
以下のシナリオを検討してください。