【问题标题】:Do I need to add hidden fields for the whole model when updating just some of the properties?仅更新某些属性时,是否需要为整个模型添加隐藏字段?
【发布时间】:2020-07-31 16:29:51
【问题描述】:

考虑这个模型和视图模型:

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")] 的意义何在?

【问题讨论】:

  • 个人所有其他字段将具有默认值。您希望知道一个属性的默认值是否是已更改的值,以及哪个是未更改且不应保留的值?
  • @SirRufo 我希望可以将除已编辑属性之外的所有其他属性的值保留在数据库中。
  • db 上下文应该如何知道 phone 属性的 null 值是一个标志。在这种情况下不更改该属性,但在任何其他情况下应将其更改为 null?
  • @SirRufo 我认为这是[Bind("PropertyName")] 的目的——上下文只会替换指定属性的值。
  • 但这与数据库上下文或 EF 完全没有关系。

标签: c# asp.net-core-mvc model-binding


【解决方案1】:

您的表单仅包含字段名称IdEmail,因此只有这些值将被发送回网络服务器(和操作方法)。 ASP.NET MVC 机制可以在您提供的对象/类中填充这些值,在本例中为 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&lt;PersonViewModel&gt;(person)); 发送的型号。但这在某种程度上有点“矫枉过正”,因为您向 html 表单发送的数据多于使用它,但它可能没问题,具体取决于您对“未使用”数据所做的其他事情。也许您应该使用return View(auto.Map&lt;UpdateEmailModel&gt;(person)); 将代码更改为新模型。

作为建议,您不应将Person 实体用作表单数据的接收类/对象。这样,数据库中的列决定了 HTML 表单必须如何命名。这也意味着由于某种原因,HTML 视图部分对存储数据的数据库有某种依赖性,这是不应该的。它应该只适用于控制器程序集中定义的模型。但这只是一个建议,显然是基于意见的。

【讨论】:

    猜你喜欢
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-26
    • 1970-01-01
    • 2015-01-26
    • 2021-11-30
    • 2011-04-15
    相关资源
    最近更新 更多