仅更新部分属性时是否需要为整个模型添加隐藏字段?

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")] 有什么意义?

您的表单仅包含字段名称 IdEmail,因此只有这些值会被发送回网络服务器(和操作方法)。 ASP.NET MVC 机制可以将这些值填充到您提供的 object/class 中,在本例中是一个 Person 对象,但所有其他值都未定义并具有默认值(如 null0、等等)。

您可以更改 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 视图部分对存储数据的数据库有某种依赖性,这是不应该的。它应该只适用于控制器程序集中定义的模型。但这只是一个建议,显然是基于个人意见。