控制器调用存储库而不是服务是不好的做法吗?
解释更多:
我发现,在好的设计控制器中,可以调用服务和服务使用存储库。
但有时在控制器中,我不需要任何逻辑,只需要从db中获取并将其传递给视图即可。
而且我可以通过调用存储库来做到这一点-无需调用服务-这是不好的做法吗?
控制器调用存储库而不是服务是不好的做法吗?
解释更多:
我发现,在好的设计控制器中,可以调用服务和服务使用存储库。
但有时在控制器中,我不需要任何逻辑,只需要从db中获取并将其传递给视图即可。
而且我可以通过调用存储库来做到这一点-无需调用服务-这是不好的做法吗?
Answers:
不,可以这样想:存储库也是一种服务。
如果您通过存储库检索的实体可以处理大多数业务逻辑,则无需其他服务。仅拥有存储库就足够了。
即使您具有某些服务,也必须通过这些服务来操作实体。首先从存储库中获取实体,然后将其传递给所述服务。能够在尝试之前就抛出HTTP 404非常方便。
同样对于读取场景,通常只需要实体将其投影到DTO / ViewModel。介于两者之间的服务层通常会导致很多通过方法,这很丑陋。
控制器直接调用存储库是不错的做法。“服务”只是另一种工具,因此请在有意义的地方使用它。
NikolaiDante评论:
...为正确的应用选择正确的模式。我要说的是您应该使应用程序保持一致。
我认为一致性不是最重要的方面。“服务”类旨在封装一些更高级别的逻辑,因此控制器不需要实现它。如果给定操作不需要“高级逻辑”,则直接进入存储库。
为了促进良好的关注点分离和可测试性,存储库应该是您通过构造函数注入到服务中的依赖项:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
如果在数据库中搜索记录需要某种形式的参数化查询,则服务类可能是接受视图模型并构建查询然后由存储库执行的好地方。
同样,如果您具有表单的复杂视图模型,则服务类可以通过在域模型/实体上调用方法,然后使用存储库来持久化记录,来封装创建,更新和删除记录的逻辑。
相反,如果您的控制器需要按其ID获取记录,则为此委派服务对象就象用大锤敲打图钉一样,远远超出了您的需求。
我发现控制器最适合处理事务或Unit of Work对象。然后,控制器或工作单元对象将委派给服务对象以进行复杂的操作,或者直接转到存储库以进行简单的操作(例如按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,并且存储库(或上下文,如果方便的话)管理数据库的工作,因此更改持久性机制不需要在上下文外部进行代码更改。