【问题标题】:Razor MVC model is losing data on Save actionRazor MVC 模型正在丢失保存操作的数据
【发布时间】:2011-03-25 17:12:29
【问题描述】:

我有 1 个使用 TextBoxFor 的文本框,其中包含数据。

我有一个模型的 ID 和一些其他基本数据,但直接在视图中显示为标签。

当我提交表单时,只有文本框字段具有模型上的数据,其他所有内容都为空,包括 Id。这意味着它不会保存到数据库中。

什么会导致除了文本框之外的所有字段都为空?

【问题讨论】:

  • 请发布说明问题的minimal(即不是您的整个应用程序)代码。包括您的视图代码以及相关的操作方法。
  • @Bugai,我知道在没有代码的情况下很难诊断问题,但是当您在 1) 视图、2) 控制器、3) 模型中有大量代码时,发布代码确实非常困难这些都包含与问题无关的上下文。
  • 无法轻松提取相关代码听起来像code smell
  • 您选择的数据持久性模型与本文相关。

标签: asp.net-mvc razor


【解决方案1】:

这是网络的工作方式,只有表单元素与表单一起提交,标签不是表单元素。

这里通常发生的是你:

  1. 呈现一个隐藏字段 (Html.Hidden / Html.HiddenFor),其中包含 Id 以及文本框
  2. 接受控制器操作中的更改(作为参数或对象)
  3. 从您的存储库/数据库中对由 Id 表示的对象的实例进行水合
  4. 将更改应用到水合实例
  5. 验证对象的状态并更新您的存储库/数据库(或您计划对其进行的任何操作)

由于发布的数据类由于缺少属性(例如标记为 [Required] 的属性)而经常“无效”,因此创建一个仅更改属性的新类(称为“命令模型”)是很常见的”)。此类可以有自己的验证属性,因此不会影响您的表单验证。

【讨论】:

  • 非常好,感谢您简洁明了的回复。这让它更清楚了,我还有很多工作要做,以消除我大脑中的网络表单心态!
【解决方案2】:

只有输入被发送回服务器。如果您希望根据页面上的数据填充模型,它们必须在输入中(或 url 的一部分)。标签元素中的数据不会与表单一起发布到服务器(这是标准的 HTML 表单行为)。通常,您会使用隐藏字段来回发不可编辑的模型数据,或者只是引用模型 ID 并从数据库中重新填充,从而更新可编辑属性(如下所示)。

例子:

 @(using Html.BeginForm( new { id = Model.ID } ))
 {
       <p>
           <label>Fixed Property:</label>
           @Model.SomeFixedProperty
       </p>
       <p>
          @Html.LabelFor( m => m.EditableProperty )
          @Html.TextBoxFor( m => m.EditableProperty )
       </p>
}

控制器

[HttpPost]
public ActionResult Foo( int id, string editableProperty )
{
    var model = repo.GetById( id );
    model.EditableProperty = editableProperty;
    repo.Save();
    return View( model );
}

【讨论】:

  • 好的,但是如果您有一个显示 10 个标签和 1 个用于编辑的标签的完整表单怎么办。我应该如何在不重置所有内容的情况下将这些数据恢复到模型中?听起来这是 ViewState 可以解决的主要问题?
  • @Jon - (1) 隐藏字段与您需要在模型中重新填充的每个事物的标签一起使用,(2) 使用 TempData 保存来自先前请求的数据,或 (3) 包括足够的信息来重新制定所需的数据。 ViewState 实际上做了 (1),尽管数据是加密的。如果您愿意,您可以复制此功能,但我不建议这样做。根据您的说法,我可能会选择 (3) 并在 url 中包含模型 ID。让您的控制器操作将 id 和更新的数据作为参数。从数据库中检索模型,只需要修改 wnat。
  • @Jon - 在您依赖 TempData 之前,请查看会话状态并了解它是如何扩展的,因为这就是 TempData 包装的内容。
【解决方案3】:

虽然我同意@RichardSzalay 的观点,但另一种方法是将未更改的属性标记为未修改。

假设您有一个具有以下属性的模型:Id、Name、Email。而且您不想更改电子邮件。

public ActionResult ChangeName([Bind(Include="Id,Name")] User model)
{
    // ...
    db.Entry(model).State = EntityState.Modified;
    db.Entry(model).Property(m => m.Email).IsModified = false;
    db.SaveChanges();
    // ...
}

缺点是您可能会因为模型中缺少字段而遇到验证问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多