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。我想我有一个操作顺序问题。值 LoanAmountLockBranchRevBranchProcessFee 作为查询结果返回:

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

2) http://www.asp.net/mvc/overview/older-versions-1/models-%28data%29/validating-with-a-service-layer-cs

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 视图模型。