我正在研究一个带有DI和ORM的ASP.NET MVC应用程序的模型。
最近,我一直在研究在服务层编写所有业务逻辑的优缺点,而不是在实体类本身中放置特定于实体的逻辑。实体类中声明的方法显然是在实体的特定实例上调用的,因此只有在从ORM查询实例化该实例时才能调用它们。
假设我有一个Product
实体,并在其上声明了ApplyDiscount
方法。如果从控制器的操作方法传入了ID
产品,我必须首先使用此ID
查询产品实例,然后调用ApplyDiscount
方法。但查询代码应该在哪里发生?在我的服务层中声明一个方法是一种有效的做法,该方法需要ID
,查询Product
实例,然后在该实例上调用ApplyDiscount
?或者该代码应该转到其他地方?
最后,我想知道是否在服务层中查询代码并且在实体类本身中具有修改代码的结果实体是在尝试避免胖服务层时的常见/正确实现。贫血领域模型。
服务层中的查询代码是否完全违背了目的?
答案 0 :(得分:0)
它没有破坏目的,但是你最终将功能(特别是验证)迁移到服务层,而不一定是。
通常,您希望尽可能早地进行验证;也就是说,如果你被赋予了无效的ID,你需要确保在通过逻辑启动执行链之前已经捕获了这个无效条件。通常,这意味着在控制器中执行查询并将结果对象传递到服务层;这会将查询功能隔离到执行链中的高级别,并且可以防止您必须在服务层中实现高级排除逻辑(例如,如果整个ID集无效,您可以执行该验证在服务层之外,从而隔离了相关逻辑,使您无需在服务层内执行此操作。
通常,请考虑以下方法:在最早的参考点执行对象级验证和反序列化,尽可能远离服务层迁移逻辑,从而“细化”您的服务层。当然,这里涉及一定程度的灵活性,但作为一般规则,这是一个很好的灵活性。
答案 1 :(得分:0)
我真的不认为这里需要服务层。如果逻辑只影响一个实体,我会把逻辑放在实体本身。 (显然你不应该相信用户的输入,我只是将其显示为假设代码。)
public ViewResult ApplyDiscount(int productId, decimal percent)
{
var product = Database.Get<Product>(productId);
product.ApplyDiscount(percent);
Database.Save(product);
return View(product);
}
产品:
public void ApplyDiscount(decimal percent)
{
this.Price = this.Price * (1 - discount);
}
答案 2 :(得分:-1)
目前我在实体上使用静态Find
方法,例如:
public ActionResult ApplyDiscount(int id, decimal percent) {
Product product = Product.Find(id);
if (product == null)
return HttpNotFound();
var result = product.ApplyDiscount(percent);
if (result.IsError)
return ViewWithErrors(result);
return RedirectToAction("DiscountApplied");
}
ApplyDiscount
返回一个带有验证错误的对象,该对象可以映射到ModelState错误。