仅更新部分属性时是否需要为整个模型添加隐藏字段?
Do I need to add hidden fields for the whole model when updating just some of the properties?
考虑这个模型和视图模型:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
仅编辑电子邮件的表单:
<form asp-action="UpdateEmail">
<input type="hidden" asp-for="Id" />
<label asp-for="Email"></label>
<input asp-for="Email" />
<button type="submit">Update e-mail address</button>
</form>
以及 UpdateEmail()
POST 控制器方法:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UpdateEmail(int id, [Bind("Id,Email")] Person person)
{
if (id != person.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
db.Update(person);
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// ... stuff
}
return RedirectToAction("Details", new { id = person.Id });
}
return View(auto.Map<PersonViewModel>(person));
}
根据我的经验,在这种情况下,除 Email
之外的所有其他属性都将被 NULL
值覆盖。我真的必须将它们添加为表单中的隐藏字段吗?如果是这样,那么使用 [Bind("Id,Email")]
有什么意义?
您的表单仅包含字段名称 Id
和 Email
,因此只有这些值会被发送回网络服务器(和操作方法)。 ASP.NET MVC 机制可以将这些值填充到您提供的 object/class 中,在本例中是一个 Person
对象,但所有其他值都未定义并具有默认值(如 null
、0
、等等)。
您可以更改 UpdateEmail()
方法签名以将表单数据保存在单独的参数中,例如:
public async Task<IActionResult> UpdateEmail(int id, string email)
从那里您可以从数据库加载实体并更改值 (or doing it directly)。
如果您想使用一个对象而不是为每个表单元素设置多个参数,您可以定义一个新模型并改为使用它:
public class UpdateEmailModel
{
public int Id { get; set; }
public string Email { get; set; }
}
那你可以把方法改成:
public async Task<IActionResult> UpdateEmail(UpdateEmailModel model)
或者您可以将类型更改为 PersonViewModel
,因为那是您发送的型号 return View(auto.Map<PersonViewModel>(person));
。但这有点 "overkill" 因为您向 html 表单发送的数据比使用它要多,但这可能没问题,具体取决于您对 "unused" 数据所做的其他操作。也许您应该使用 return View(auto.Map<UpdateEmailModel>(person));
.
将代码更改为新模型
建议您不要使用 Person
实体作为表单数据的接收 class/object。这样,数据库中的列就规定了 HTML 表单必须如何命名。这也意味着由于某种原因 HTML 视图部分对存储数据的数据库有某种依赖性,这是不应该的。它应该只适用于控制器程序集中定义的模型。但这只是一个建议,显然是基于个人意见。
考虑这个模型和视图模型:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
仅编辑电子邮件的表单:
<form asp-action="UpdateEmail">
<input type="hidden" asp-for="Id" />
<label asp-for="Email"></label>
<input asp-for="Email" />
<button type="submit">Update e-mail address</button>
</form>
以及 UpdateEmail()
POST 控制器方法:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UpdateEmail(int id, [Bind("Id,Email")] Person person)
{
if (id != person.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
db.Update(person);
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// ... stuff
}
return RedirectToAction("Details", new { id = person.Id });
}
return View(auto.Map<PersonViewModel>(person));
}
根据我的经验,在这种情况下,除 Email
之外的所有其他属性都将被 NULL
值覆盖。我真的必须将它们添加为表单中的隐藏字段吗?如果是这样,那么使用 [Bind("Id,Email")]
有什么意义?
您的表单仅包含字段名称 Id
和 Email
,因此只有这些值会被发送回网络服务器(和操作方法)。 ASP.NET MVC 机制可以将这些值填充到您提供的 object/class 中,在本例中是一个 Person
对象,但所有其他值都未定义并具有默认值(如 null
、0
、等等)。
您可以更改 UpdateEmail()
方法签名以将表单数据保存在单独的参数中,例如:
public async Task<IActionResult> UpdateEmail(int id, string email)
从那里您可以从数据库加载实体并更改值 (or doing it directly)。
如果您想使用一个对象而不是为每个表单元素设置多个参数,您可以定义一个新模型并改为使用它:
public class UpdateEmailModel
{
public int Id { get; set; }
public string Email { get; set; }
}
那你可以把方法改成:
public async Task<IActionResult> UpdateEmail(UpdateEmailModel model)
或者您可以将类型更改为 PersonViewModel
,因为那是您发送的型号 return View(auto.Map<PersonViewModel>(person));
。但这有点 "overkill" 因为您向 html 表单发送的数据比使用它要多,但这可能没问题,具体取决于您对 "unused" 数据所做的其他操作。也许您应该使用 return View(auto.Map<UpdateEmailModel>(person));
.
建议您不要使用 Person
实体作为表单数据的接收 class/object。这样,数据库中的列就规定了 HTML 表单必须如何命名。这也意味着由于某种原因 HTML 视图部分对存储数据的数据库有某种依赖性,这是不应该的。它应该只适用于控制器程序集中定义的模型。但这只是一个建议,显然是基于个人意见。