ASP.NET MVC 5 模型绑定编辑视图

2023-12-27

我无法想出一个最好的口头描述和少量代码的问题解决方案。我正在使用 VS 2013、MVC 5 和 EF6 代码优先;我还使用 MvcControllerWithContext 脚手架,它生成支持 CRUD 操作的控制器和视图。

简而言之,我有一个包含 CreatedDate 值的简单模型:

public class WarrantyModel
{
    [Key]
    public int Id { get; set; }
    public string Description { get; set; }
    DateTime CreatedDate { get; set; }
    DateTime LastModifiedDate { get; set; }
}

包含的 MVC 支架对其索引、创建、删除、详细信息和编辑视图使用相同的模型。我want“创建”视图中的 CreatedDate;我do not希望它出现在“编辑”视图中,因为我不希望在编辑视图回发到服务器时更改其值,并且我不希望任何人能够在表单发布期间篡改该值。

理想情况下,我不希望 CreatedDate 进入编辑视图。我找到了一些可以放置在模型的 CreatedDate 属性上的属性(例如,[ScaffoldColumn(false)]),以防止它出现在编辑视图上,但随后我在回发时收到绑定错误,因为 CreatedDate 最终会出现值为 1/1/0001 12:00:00 AM。这是因为“编辑”视图没有将 CreatedDate 字段的值传递回控制器。

我不想实现需要任何 SQL Server 更改的解决方案,例如在保存 CreatedDate 值的表上添加触发器。如果我想做一个快速修复,我会在显示编辑视图之前存储 CreatedDate(当然是服务器端),然后在回发时恢复 CreatedDate - 这将让我更改 1/1/0001 日期到渲染视图之前从数据库中提取的 CreatedDate EF6。这样,我可以将 CreatedDate 作为隐藏表单字段发送,然后在回发后在控制器中覆盖其值,但我没有一个好的策略来存储服务器端值(我不想使用 Session 变量或查看包)。

我查看了使用 [Bind(Exclude="CreatedDate")],但这没有帮助。

我的控制器的编辑回发功能中的代码如下所示:

public ActionResult Edit([Bind(Include="Id,Description,CreatedDate,LastModifiedDate")] WarrantyModel warrantymodel)
{
    if (ModelState.IsValid)
    {
        db.Entry(warrantymodel).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(warrantymodel);
}

我想我也许能够检查 db.Entry(warrantymodel) 对象if上面的块并检查 CreatedDate 的 OriginalValue,但是当我尝试访问该值(如下所示)时,我收到“System.InvalidOperationException”类型的异常:

var originalCreatedDate = db.Entry(warrantymodel).Property("CreatedDate").OriginalValue;

如果我能够成功检查原始 CreatedDate 值(即数据库中已有的值),我就可以覆盖 CurrentValue 的值。但由于上面的代码行生成异常,我不知道还能做什么。 (我考虑过在数据库中查询该值,但这很愚蠢,因为在呈现“编辑”视图之前已经在数据库中查询了该值)。

我的另一个想法是将 CreatedDate 值的 IsModified 值更改为 false,但是当我调试时,我发现它已经在前面显示的“if”块中设置为 false:

bool createdDateIsModified = db.Entry(warrantymodel).Property("CreatedDate").IsModified;

我不知道如何处理这个看似简单的问题。总之,我不想将模型字段传递到编辑视图,并且当视图中的其他编辑字段回发并保留到数据库时,我希望该字段(本例中为 CreatedDate)保持其原始值db.SaveChanges()。

任何帮助/想法将不胜感激。

谢谢。


您应该利用 ViewModel:

public class WarrantyModelCreateViewModel
{
    public int Id { get; set; }
    public string Description { get; set; }
    DateTime CreatedDate { get; set; }
    DateTime LastModifiedDate { get; set; }
}

public class WarrantyModelEditViewModel
{
    public int Id { get; set; }
    public string Description { get; set; }
    DateTime LastModifiedDate { get; set; }
}

ViewModel 的意图与域模型的意图有些不同。它为视图提供了正确渲染所需的足够信息。

ViewModel 还可以保留根本不属于您的域的信息。它可以保存对表或搜索过滤器上的排序属性的引用。这些对于你的领域模型来说肯定没有意义!

现在,在控制器中,您将属性从 ViewModel 映射到域模型并保留更改:

public ActionResult Edit(WarrantyModelEditViewModel vm)
{
    if (ModelState.IsValid)
    {
        var warrant = db.Warranties.Find(vm.Id);
        warrant.Description = vm.Description;
        warrant.LastModifiedDate = vm.LastModifiedDate;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(warrantymodel);
}

此外,ViewModel 非常适合合并来自多个模型的数据。如果您有保修的详细视图,但您还想查看该保修下完成的所有服务,该怎么办?您可以简单地使用这样的 ViewModel:

public class WarrantyModelDetailsViewModel
{
    public int Id { get; set; }
    public string Description { get; set; }
    DateTime CreatedDate { get; set; }
    DateTime LastModifiedDate { get; set; }
    List<Services> Services { get; set; }
}

ViewModel 简单、灵活且非常流行。这是对它们的一个很好的解释:http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

您最终将编写大量映射代码。Automapper非常棒,可以完成大部分繁重的工作:http://automapper.codeplex.com/ http://automapper.codeplex.com/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET MVC 5 模型绑定编辑视图 的相关文章

随机推荐