如何处理MVC中的提交模型是最佳实践?

4

我很新于MVC,仍然不清楚在两种情况下获得相同结果的最佳和适当方式。假设某些用户应该为特定根类别添加新的子类别。

情况1: SubCategory是由EF映射的类,其中所有属性都不可为空。

控制器:

    [Authorize]
    public ActionResult Create()
    {
        SubCategory subCategory = new SubCategory();

        subCategory.RootCategoryID = 1;

        return View(subCategory);
    }

    [Authorize]
    [HttpPost]
    public ActionResult Create(SubCategory thisSubCategory)
    {
        if (ModelState.IsValid)
        {
           //And some BL logic called here to handle new object...
        }
    }

视图:

    @Html.HiddenFor(model => model.ID)

    @Html.HiddenFor(model => model.RootCategoryID)

    <h3>Sub Category Name: </h3>

    @Html.EditorFor(model => model.CategoryName)

    @Html.ValidationMessageFor(model => model.CtaegoryName)

    <input id="btnAdd" type="submit" value="Add" />

案例 2: 将辅助类作为控制器的模型,并在提交后填充 EF 对象

控制器:

    class SubCategoryHelper
    {
       public string Name { get; set; }
    }

    [Authorize]
    public ActionResult Create()
    {
       SubCategoryHelper subCategory = new SubCategoryHelper();

       return View(subCategory);
    }

    [Authorize]
    [HttpPost]
    public ActionResult Create(SubCategoryHelper thisSubCategory)
    {
        if (ModelState.IsValid)
        {
           SubCategory newSubCategory = new SubCategory();

           newSubCategory.RootCategoryID = 1;

           newSubCategory.CtaegoryName = thisSubCategory.Name;

           //And some BL logic called here to handle new object...
        }
    }

查看:

子类别名称:

    @Html.EditorFor(model => model.Name)

    @Html.ValidationMessageFor(model => model.Name)

    <input id="btnAdd" type="submit" value="Add" />

两种方法都可以达到相同的效果,但第一种方法看起来不太安全,因为客户端可能会更改隐藏字段。第二种方法要长得多,想象一下对于像客户或产品这样的复杂对象的相同方式......我应该选择哪种?还是有其他方法吗?


这是一个常见的问题。第一种方法非常适合简单的需求。但它也可能成为麻烦的源头,例如它经常从视图生成数据库查询(由于惰性加载)。第二种方法被称为ViewModel模式,是一种广泛采用的编码方式。然而,它增加了将实体<->viewModel进行映射的负担。 - pkmiec
2个回答

2

第一种情况适用于简单性。如果您扩展模型,则需要在较少的位置进行更改。这不是不安全的。您可以通过多种方式绕过创建或绑定隐藏输入字段。

使用BindAttribute绕过属性绑定:

ActionResult Create([Bind(Exclude = "RootCategoryId")]
                    SubCategoryHelper thisSubCategory) {//....}

或者在模型类属性上使用 ScaffoldColumnAttribute(例如在使用编辑模板时):

[ScaffoldColumn(false)]
public int RootCategoryId {get; set;}

或者完全不公开它(就像您在示例中使用Html.HiddenInput助手一样)。
您描述的第二种方法通常称为ViewModel模式。它鼓励将您的演示层和域层分离。优点是,您的领域模型不会被演示层特定代码(如各种显示属性等)污染。但是,它带来了另一个映射域模型和视图模型之间的工作量。
可能没有普遍适用的经验法则。这取决于您的应用程序类型。
如果基本上是一些简单的数据驱动CRUD应用程序,则可以轻松地使用第一个选项。然而,当您的应用程序变得更大时,您肯定会欣赏在独立层上自由操作的自由。如果您的BLL代码与ASP MVC以外的其他“客户端”(Web服务,桌面等)一起使用,我肯定会选择第二个选项。
我还建议阅读这篇伟大的文章:是否值得映射分层

2
无论是我工作的小项目还是大项目,我总是选择案例2,将我的数据层(Entity Framework)和UI层分开。特别是在使用Entity Framework时,因为这些对象可能变得非常庞大,你传递的很多东西其实并不需要。
不要称之为“Helper”类,而是称之为“ViewModel”或“Model”。在你的情况下,应该称之为“SubCategoryViewModel”。
public class SubCategoryViewModel
{
   public int Id {get;set;}
   public int RootCategoryId {get;set;}
   [Required]
   public string Name { get; set; }
}

[Authorize]
public ActionResult Create()
{
   var subCategoryViewModel = new SubCategoryViewModel();

   return View(subCategoryViewModel);
}

[Authorize]
[HttpPost]
public ActionResult Create(SubCategoryViewModel viewModel)
{
    if (ModelState.IsValid)
    {
       var subCategory = new SubCategory();

       subCategory.RootCategoryID = 1;

       subCategory.CategoryName = viewModel.Name;

       //And some BL logic called here to handle new object...

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接