在 MVC (CRUD) 中创建模型的最佳实践

Hun*_*son 0 c# model-view-controller asp.net-mvc asp.net-mvc-viewmodel

所以我们在团队中增加了一名新程序员,他对如何在 MVC 中创建模型有一些想法,这与我们之前创建模型的方式不同。例如,我们有一个系统,用户可以在其中提交文件请求,并且该系统中有一个页面,用户可以在其中计算完成该文件请求的费用。此费用创建页面可以输入有关费用的一些数据以及相关发票。用户可以添加发票行项目并使用它们来自动计算费用总额。在这种情况下,我们通常会创建如下所示的模型。

    public class Fee
{
    public virtual Guid RequestID { get; set; }
    public virtual Guid FeeID { get; set; }
    public string FeeTitle { get; set; }
    public decimal FeeAmount { get; set; }
    public DateTime? DueDate { get; set; }
    public decimal AmountPaid { get; set; }
    public Invoice Invoice { get; set; }
    public List<InvoiceLineItem> LineItems { get; set; }
}

public class Invoice
{ 
    // Additional Invoice Data (To, From, etc)
}

public class InvoiceLineItem
{
    public string LineItemTitle { get; set; }
    public int Quantity { get; set; }
    public decimal PricePerUnit { get; set; }
    public decimal Subtotal { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

我们的新程序员认为这不是一个好方法,因为不同的操作有不同的数据需求。例如,当您创建费用时,您需要知道相应的请求 ID。但是,当您更新费用时,您只需要知道费用 ID。因此,当他创建他的模型时,他以这样一种方式创建它们,即存在多个继承层,以努力控制在服务层中更新并呈现在视图上的数据。他的想法是,我们应该能够假设为交易传入的任何模型都应该使用其所有数据点,而不必根据情况猜测数据是什么。

对我来说,这给我们的模型增加了大量不必要的复杂性,并使在其他模块上使用它们变得更加困难。下面是一个示例,说明了这一点。

 /// <summary>
/// This model is used to present data in a read fashion to the end user
/// </summary>
public class FeeViewModel : FeeModel_Create
{
    public string FullRequestNumber { get; set; }
    public decimal Balance { get; set; }
    public List<String> States { get; set; }
    public List<FeeAttachmentEditModel> Attachments { get; set; }
    public List<PaymentViewModel> Payments { get; set; }

}

/// <summary>
/// This model adds a request id to the fee update model because we need to know which request this fee is associated with
/// </summary>
public class FeeModel_Create : FeeModel_Update
{
    public Guid RequestID { get; set; }

}

/// <summary>
/// Represents the parameters required to update a fee
/// </summary>
public class FeeModel_Update
{
    public virtual Guid FeeID { get; set; }
    public decimal FeeAmount { get; set; }
    public DateTime? DueDate { get; set; }
    public string FeeTitle { get; set; }
    public decimal AmountPaid { get; set; }
    public List<MaterialList> MaterialTypes { get; set; }
    public List<InvoiceLineItem_Adhoc> LineItems { get; set; }
    public Invoice Invoice { get; set; }


    public void InjectValuesIntoInvoiceModel(Invoice Invoice)
    {
        Invoice.Description = this.Invoice.Description;
        Invoice.Terms = this.Invoice.Terms;
        Invoice.To_Name = this.Invoice.To_Name;
        Invoice.To_Address = this.Invoice.To_Address;
        Invoice.To_Address2 = this.Invoice.To_Address2;
        Invoice.To_City = this.Invoice.To_City;
        Invoice.To_State = this.Invoice.To_State;
        Invoice.To_Zip = this.Invoice.To_Zip;
        Invoice.From_Name = this.Invoice.From_Name;
        Invoice.From_Address = this.Invoice.From_Address;
        Invoice.From_Address2 = this.Invoice.From_Address2;
        Invoice.From_City = this.Invoice.From_City;
        Invoice.From_State = this.Invoice.From_State;
        Invoice.From_Zip = this.Invoice.From_Zip;
    }
}


public class InvoiceLineItem_Adhoc
{
    public string Type { get; set; }
    public string EnteredBy { get; set; }
    public decimal Quantity { get; set; }
    public decimal UnitCost { get; set; }
    public InvoiceLineItem ToLineItem(Guid InvoiceID)
    {
        var lineItem = new InvoiceLineItem();
        StaticValueInjecter.InjectFrom(lineItem, this);
        lineItem.InvoiceLineItemID = Guid.NewGuid();
        lineItem.InvoiceID = InvoiceID;
        lineItem.UserID = 1;
        return lineItem;
    }
}

public class PaymentViewModel
{
    public Guid RequestID { get; set; }
    public Guid FeeID { get; set; }
    public string FullRequestNumber { get; set; }
    public string FeeTitle { get; set; }
    public virtual Guid PaymentID { get; set; }
    public decimal PaymentAmount { get; set; }
    public Nullable<System.DateTime> DatePaid { get; set; }
}

public class FeeAttachmentEditModel
{
    public Guid RequestID { get; set; }
    public Guid FeeID { get; set; }
    public string FullRequestNumber { get; set; }
    public string FeeTitle { get; set; }
    public virtual System.Guid FeeAttachmentID { get; set; }
    public System.Guid AttachmentTypeID { get; set; }
    public string AttachmentName { get; set; }
    public byte[] Data { get; set; }
    public string Extension { get; set; }
    public string mimeType { get; set; }
    public string AttachmentBody { get; set; }
    public HttpPostedFileBase FileUpload { get; set; }
    public string FileName { get; set; }

    public bool HadError = false;
}
Run Code Online (Sandbox Code Playgroud)

我只是在这里寻找关于在 MVC 中创建模型的最佳实践的答案。您是否应该通过继承部分类或其他方式创建单独的模型,以适应您正在执行的创建、读取、更新或删除操作。或者最好有一个视图模型来转换为视图呈现/传递的内容,以及在访问数据时过滤掉来自视图模型的重要内容的逻辑?

Kei*_*eau 5

我们采用的典型方法是拥有一个与视图紧密耦合且仅包含该信息的 ViewModel。InputModels 也是一样,它们应该只包含将传入的属性。至于继承部分,我将远离这种方法。只需创建简单、扁平的 DTO 并从您的域模型中映射它们。应该没有逻辑,因此 DRY 并不真正适用于您应用程序的这一层。