MVC - 数据计算的最佳实践 - viewmodel与controller

时间:2015-07-30 17:45:23

标签: c# asp.net-mvc asp.net-mvc-5.1

我需要一些关于在何处运行数据计算的建议。

我有一个viewmodel,其中包含我计算所需的所有字段,并为计算之一创建了以下字段:

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);
}

我最初能够通过在查询中填充viewmodel后在控制器中完成所有数学计算来实现这些计算,但是会有大约10个计算,根据我的理解,我不应该这样做用业务逻辑弄乱我的控制器。

最佳解决方案是什么?我是否需要为计算创建另一个类?如果是这样,我如何用我的数据填充该类并在我的控制器中使用它?

编辑:我不确定如何设置业务类并在控制器中使用它们。任何人都可以指向我的教程方向吗?

3 个答案:

答案 0 :(得分:6)

您不应在控制器或视图模型中进行计算。您应该在业务层中执行此操作。想想View Models是非常简单的类,包含要向用户显示的数据,就是它。

关于计算,您应将其中一个术语转换为十进制,而不是计算结果。如果你除以整数,你会得到一个整数。

例如,您可以创建一个类并将其命名为CommissionService。该类应调用您的数据层来获取数据,进行任何额外的计算并将数据(可能是DTO)返回给控制器。控制器应该基于DTO创建视图模型并将它们发送到视图。

enter image description here

阅读这些文章:

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

答案 1 :(得分:2)

首先,您在控制器上分配给CommissionVM的属性与模型上声明的属性不匹配。如果模型上只有LoanAmountLock和BranchRevs,则可以分配Loan和BranchRevenues。 请注意,Loan属性本身就是一个对象,并且必须从该对象(Loan.LoanAmountLock)中检索LoanAmountLock。 BranchRevenues对象也是如此。您应该根据需要将BranchRevs分配给BranchRevenues对象的相应属性。如果你不这样做,那么值将默认为0,当尝试计算BranchGrossTotal时,它显然是0。

假设您正确填充模型属性,另一个原因是FirstOrDefault方法因为没有这样的实体而呈现空值。这将导致BranchGrossTotal为0。

你是对的,你既不需要计算也不需要使用db访问来控制你的控制器。我将创建一个商业类ComissionBusiness并在控制器的顶部实例化它。这个类有一个执行所有计算的方法。您应该将Reconcile方法移动到新的业务类方法,并在协调操作上调用它。有点像(借口缺乏语法)

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);
}
}

答案 2 :(得分:2)

我不喜欢在我的视图模型上进行计算 - 您无法在其他地方轻松地重复使用计算,并且测试和调试更加困难。创建单独的类来执行业务逻辑。

您的业务逻辑类可以返回视图模型,也可以返回用于填充这些模型的值。权衡是易用性和可重用性。

我通常倾向于返回值而不是大对象,因此我的服务更可重用。

<强>控制器

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()中完全填充并返回视图模型。