MVC - 数据计算最佳实践 - 视图模型与控制器
MVC - data calculations best practice - viewmodel vs. controller
r我需要一些关于在哪里运行计算数据的建议。
我有一个视图模型,其中包含计算所需的所有字段,并且我为其中一个计算创建了以下内容:
public class CommissionVM
{
public int? LoanAmountLock { get; set; } // from loan table
public decimal BranchRev { get; set; } // from revenue table
public decimal BranchProcessFee { get; set; } // from revenue table
public decimal BranchGrossTotal
{
get
{
return Convert.ToDecimal(LoanAmountLock * (BranchRev/ 100) + BranchProcessFee);
}
}
}
我试图在我的视图中使用 Model.BranchGrossTotal,但它返回 0。我想我有一个操作顺序问题。值 LoanAmountLock
、BranchRev
和 BranchProcessFee
作为查询结果返回:
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM()
{
Loan = db.Loan.FirstOrDefault(a => a.id == id ),
BranchRevenues = db.BranchRevenues.FirstOrDefault(a => a.RevenueLoanType == RevenueLoanType),
};
return View(model);
}
在我用查询填充视图模型之后,我最初能够通过在控制器中进行所有数学运算来使这些计算起作用,但是大约会有 10 次计算,据我所知,我不应该用业务逻辑弄乱我的控制器。
最好的解决方案是什么?我需要为计算创建另一个 class 吗?如果是这样,我如何用我的数据填充 class 并在我的控制器中使用它?
编辑:我不确定如何设置业务 classes 并在控制器中使用它们。谁能指出教程的方向?
您不应在控制器或视图模型中进行计算。您应该在业务层中执行此操作。想想视图模型真的很简单 class 包含要显示给用户的数据,仅此而已。
关于计算,您应该将其中一项转换为小数,而不是计算结果。如果你除以整数,你会得到一个整数。
例如,您可以创建一个 class 并将其命名为 CommissionService。 class 应该调用你的数据层来获取数据,做任何额外的计算和 return 数据(可能是 DTO)到控制器。控制器应该基于 DTO 创建视图模型并将它们发送到视图。
阅读这些文章:
1) https://msdn.microsoft.com/en-us/library/hh404093.aspx
3) http://blog.diatomenterprises.com/asp-net-mvc-business-logic-as-a-separate-layer/
4) http://sampathloku.blogspot.com.ar/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
首先,您在控制器上分配给 CommissionVM 的属性与模型上声明的属性不匹配。当您的模型上只有 LoanAmountLock 和 BranchRevs 可用时,您分配 Loan 和 BranchRevenues。
请注意 Loan 属性 本身是一个对象,必须从该对象 (Loan.LoanAmountLock) 中检索 LoanAmountLock。 BranchRevenues 对象也是如此。您应该根据需要将 BranchRevs 分配给 BranchRevenues 对象的相应 属性。如果您不这样做,那么这些值将默认为 0,并且在尝试计算 BranchGrossTotal 时,它显然将为 0。
假设您正确填充了模型属性,另一个原因是 FirstOrDefault 方法呈现空值,因为没有这样的实体。这也会导致 BranchGrossTotal 为 0。
你是对的,你不需要让你的控制器变得混乱,无论是计算还是数据库访问。我会创建一个业务 class ComissionBusiness 并在您的控制器顶部实例化它。 class 将有一个执行所有计算的方法。您应该将 Reconcile 方法移动到新的业务 class 方法,并在协调操作中调用它。类似于(请原谅缺乏语法)
public MyController : Controller {
public ComissionBusiness comissionBusiness;
public MyController(){
comissionBusiness = new ComissionBusiness();
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = comissionBusiness.Reconcile(id, revenueLoanType);
return View(model);
}
}
我不喜欢在我的视图模型上进行计算——您无法在其他地方轻松地重用该计算,而且它更难测试和调试。创建单独的 类 来执行业务逻辑。
您的业务逻辑 类 可以 return 您的视图模型或 return 用于填充这些模型的值。权衡是易用性和可重用性。
我通常更喜欢 return 值而不是大对象,因此我的服务更可重用。
控制器
public class BranchController : Controller
{
private IBusinessService service;
public BranchController()
{
this.service = new BusinessService(db);
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM
{
BranchGrossTotal = this.service.GetBranchGrossTotal(id, RevenueLoanType),
...
};
return View(model);
}
}
服务
你可以制作任意数量的这些,你的控制器会根据需要使用它们。如果您需要查询,您应该传递 DbContext 实例,否则您可能会在单独的上下文中遇到相关实体的问题。
public interface IBusinessService
{
decimal GetBranchGrossTotal(int id, string revenueLoanType);
}
public class BusinessService : IBusinessService
{
private DbContext db;
public BusinessService(DbContext db)
{
this.db = db;
}
public decimal GetBranchGrossTotal(int id, string revenueLoanType)
{
var branch = db.Branch.First(b => b.Id == id);
// do stuff
return total;
}
}
如果您愿意,您可以在 GetBranchGrossTotal()
中完全填充和 return 视图模型。
r我需要一些关于在哪里运行计算数据的建议。
我有一个视图模型,其中包含计算所需的所有字段,并且我为其中一个计算创建了以下内容:
public class CommissionVM
{
public int? LoanAmountLock { get; set; } // from loan table
public decimal BranchRev { get; set; } // from revenue table
public decimal BranchProcessFee { get; set; } // from revenue table
public decimal BranchGrossTotal
{
get
{
return Convert.ToDecimal(LoanAmountLock * (BranchRev/ 100) + BranchProcessFee);
}
}
}
我试图在我的视图中使用 Model.BranchGrossTotal,但它返回 0。我想我有一个操作顺序问题。值 LoanAmountLock
、BranchRev
和 BranchProcessFee
作为查询结果返回:
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM()
{
Loan = db.Loan.FirstOrDefault(a => a.id == id ),
BranchRevenues = db.BranchRevenues.FirstOrDefault(a => a.RevenueLoanType == RevenueLoanType),
};
return View(model);
}
在我用查询填充视图模型之后,我最初能够通过在控制器中进行所有数学运算来使这些计算起作用,但是大约会有 10 次计算,据我所知,我不应该用业务逻辑弄乱我的控制器。
最好的解决方案是什么?我需要为计算创建另一个 class 吗?如果是这样,我如何用我的数据填充 class 并在我的控制器中使用它?
编辑:我不确定如何设置业务 classes 并在控制器中使用它们。谁能指出教程的方向?
您不应在控制器或视图模型中进行计算。您应该在业务层中执行此操作。想想视图模型真的很简单 class 包含要显示给用户的数据,仅此而已。
关于计算,您应该将其中一项转换为小数,而不是计算结果。如果你除以整数,你会得到一个整数。
例如,您可以创建一个 class 并将其命名为 CommissionService。 class 应该调用你的数据层来获取数据,做任何额外的计算和 return 数据(可能是 DTO)到控制器。控制器应该基于 DTO 创建视图模型并将它们发送到视图。
阅读这些文章:
1) https://msdn.microsoft.com/en-us/library/hh404093.aspx
3) http://blog.diatomenterprises.com/asp-net-mvc-business-logic-as-a-separate-layer/
4) http://sampathloku.blogspot.com.ar/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
首先,您在控制器上分配给 CommissionVM 的属性与模型上声明的属性不匹配。当您的模型上只有 LoanAmountLock 和 BranchRevs 可用时,您分配 Loan 和 BranchRevenues。 请注意 Loan 属性 本身是一个对象,必须从该对象 (Loan.LoanAmountLock) 中检索 LoanAmountLock。 BranchRevenues 对象也是如此。您应该根据需要将 BranchRevs 分配给 BranchRevenues 对象的相应 属性。如果您不这样做,那么这些值将默认为 0,并且在尝试计算 BranchGrossTotal 时,它显然将为 0。
假设您正确填充了模型属性,另一个原因是 FirstOrDefault 方法呈现空值,因为没有这样的实体。这也会导致 BranchGrossTotal 为 0。
你是对的,你不需要让你的控制器变得混乱,无论是计算还是数据库访问。我会创建一个业务 class ComissionBusiness 并在您的控制器顶部实例化它。 class 将有一个执行所有计算的方法。您应该将 Reconcile 方法移动到新的业务 class 方法,并在协调操作中调用它。类似于(请原谅缺乏语法)
public MyController : Controller {
public ComissionBusiness comissionBusiness;
public MyController(){
comissionBusiness = new ComissionBusiness();
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = comissionBusiness.Reconcile(id, revenueLoanType);
return View(model);
}
}
我不喜欢在我的视图模型上进行计算——您无法在其他地方轻松地重用该计算,而且它更难测试和调试。创建单独的 类 来执行业务逻辑。
您的业务逻辑 类 可以 return 您的视图模型或 return 用于填充这些模型的值。权衡是易用性和可重用性。
我通常更喜欢 return 值而不是大对象,因此我的服务更可重用。
控制器
public class BranchController : Controller
{
private IBusinessService service;
public BranchController()
{
this.service = new BusinessService(db);
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM
{
BranchGrossTotal = this.service.GetBranchGrossTotal(id, RevenueLoanType),
...
};
return View(model);
}
}
服务
你可以制作任意数量的这些,你的控制器会根据需要使用它们。如果您需要查询,您应该传递 DbContext 实例,否则您可能会在单独的上下文中遇到相关实体的问题。
public interface IBusinessService
{
decimal GetBranchGrossTotal(int id, string revenueLoanType);
}
public class BusinessService : IBusinessService
{
private DbContext db;
public BusinessService(DbContext db)
{
this.db = db;
}
public decimal GetBranchGrossTotal(int id, string revenueLoanType)
{
var branch = db.Branch.First(b => b.Id == id);
// do stuff
return total;
}
}
如果您愿意,您可以在 GetBranchGrossTotal()
中完全填充和 return 视图模型。