ASP.NET MVC中UpdateModel的正确行为是什么?

时间:2009-08-07 03:35:22

标签: asp.net-mvc updatemodel formcollection

我很想知道你们认为应该被视为ASP.NET MVC中UpdateModel方法的“正确行为”。

我在这里问的原因可能是,如果这个功能是“按设计”,有人可以澄清为什么它是这样的,也许是一种方式来调用它来实现所需的功能,我想这将是90%的人会希望这种方式发挥作用吗?

从本质上讲,我的抱怨在于UpdateModel内的绑定过程的行为。

假设您希望通过简单的Save操作方法更新表单,表单上的数据字段反映了数据库中的模型,最初要保存请求,我们可能会从中获取现有模型数据库,然后更新已更改的相关字段,通过FormCollection发送,然后由UpdateModel更新为现有模型。这个函数,但是看起来这个DB填充对象的任何现有属性都被“重置”;并且我的意思是,被设置为null或初始化默认值就像它是一个全新的对象一样,除了显然那些与FormCollection中的那些匹配。

这是一个问题,因为对象上存在的任何现有属性,但不一定存在于表单上,例如任何子集合或对象,日期或任何非UI面向字段都是空的,只留下一半 - 填充的,或多或少无法使用的对象,由于所有丢失的数据(包括现在可能已设置为0的ID堆栈)而无法保存到DB。

我认为这不是理想的行为,UpdateModel应该只更新FormCollection中找到属性匹配的属性。这意味着您的所有现有属性都将保持不变,但您的更新将被设置。但是,从目前为止所推断的内容来看,显然并非如此 - 它似乎实例化了一个全新的副本,该对象从表单中更新属性,然后返回新对象。

最后,为了明确这是多少负担,保存半复杂形式并保留所有现有对象数据的唯一方法是手动结婚每个具有相应表单属性的属性,绝对保证只更新表单中存在的属性。

我想,

  1. 那些同意这个是设计的人,是我采用最佳方式结婚的方法吗?
  2. 或者,你是怎么解决这个问题的?
  3. 请随时提出您对这些家伙的看法,谢谢。

    这是另一个遭受这个问题的人的例子:
    Calling UpdateModel with a collection of complex data types reset all non-bound values?

4 个答案:

答案 0 :(得分:15)

您使用UpdateModel()遇到的行为听起来就像是列表绑定,在这种情况下,UpdateModel()将清除列表中的内容并重新填充它。有关此问题的讨论,请参阅Hanselman's blog。如果您正在更新单个对象,UpdateModel()将更新该单个对象,从而保留没有相应表单值的属性。

其中许多问题归结为UpdateModel()实际上是基于表单输入重新填充视图模型 - 而不是域模型。 (我通过说视图模型只是控制器和视图之间的契约来略微简化,而您的域模型可能是LINQ2SQL或EF模型对象。)所有MVC教程和演示都显示UpdateModel()用于数据库对象,我觉得这是不幸的,因为它有点误导模型绑定的预期目的。 Robert的帖子更能说明UpdateModel()的实际意图。

答案 1 :(得分:5)

我相信你对UpdateModel的行为是正确的。

但是,ASP.NET MVC遵循“往返”模型,这意味着您的表单应该已经包含了生成完整记录所需的所有字段,因为您将所有字段的值都推送到视图中,或者您要求用户提供所有字段。

这种往返概念非常重要。请记住,在真正的MVC模型中,没有状态概念。您从数据库表中检索数据,将此数据推送到视图,数据显示给用户,程序停止。用户编辑数据,单击您的发布按钮,视图将数据发布到控制器方法,数据保存到数据库中,程序停止。从一个操作到下一个操作都没有依赖关系。

这种不保留记录和数据结构的部分状态的做法使得编写可以很好地扩展并且表现良好的应用程序非常简单(特别是对于浏览器中的后退按钮等)。

答案 2 :(得分:2)

我非常高兴地使用UpdateModel来处理非列表类型。我总是小心指定includeProperties数组(不是因为这个问题的潜在可能性,但是为了安全性 - 你希望用户能够破解表单(非常简单)并提交日期等吗?)。 / p>

这并不是说它无法进一步改善。

此外,在设置要求时要记住一个实际要点:对于接收POST的Web服务器,空字段与不存在的字段相同。这意味着如果UpdateModel被设计为不会“重置”不存在的表单字段(例如日期),则相同的行为意味着如果用户删除了日期字段和帖子中的文本,则不会更新with empty(或null)。

詹姆斯

答案 3 :(得分:2)

  

但我仍然对这个想法感到困惑   代表我的整个对象模型   一个表格,特别是如果说我有2   子对象和几个列表,   我不确定这是多么容易   映射通过;一堆隐藏   描绘整个物体的字段   地图?看起来很奇怪。

为此,您需要查看SubControllers和RenderAction等内容。你可以谷歌那些。我经常使用RenderAction。它允许我从自己的控制器方法将窗口小部件注入页面,而不必将单独的数据推送到ViewData。

  

我认为不应该有人这么做   保证您希望更新的任何数据   你的数据库模型应该存在   完全在表格上。我不认为我   有一个db表可以   促进这一点,考虑“创造   日期“例如,或”更新日期“,   我觉得这不太理想   将它存储在隐藏的字段中   形式。

你是对的。像CreationDate,UpdatedBy这样的东西应该在Controller中处理(实际上是存储库,如果你使用的是存储库)。到那时,您应该已经拥有视图模型中所需的所有字段来更新数据库。

您可能需要使用“强类型视图模型”对象。如果您不是或不确定,请查看此页面:http://nerddinnerbook.s3.amazonaws.com/Part6.htm