【问题标题】:What is correct behaviour of UpdateModel in ASP.NET MVC?ASP.NET MVC 中 UpdateModel 的正确行为是什么?
【发布时间】:2010-11-17 14:01:14
【问题描述】:

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

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

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

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

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

我认为这是不可取的行为,UpdateModel 应该只更新在FormCollection 中找到属性匹配的属性。这意味着您现有的所有属性都不会受到影响,但您的更新将被设置。然而,从目前的推论来看,显然情况并非如此——它似乎实例化了一个对象的全新副本,更新表单的属性,然后返回新对象。 p>

最后,从这个负担的角度来看,保存半复杂表单并保留所有现有对象数据的唯一方法是手动合并每个 属性与相应的表单属性,以绝对保证仅更新表单中存在的属性。

我猜,

  1. 那些同意这是有意为之的人,我的形式结合是最好的方式吗?
  2. 或者,您是如何解决这个问题的?

请随时发表您对这些人的看法,谢谢。

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

【问题讨论】:

  • 我很想看看其他人的想法,因为我碰巧同意你的观点。必须有一种正确、更优雅的方式来处理这个问题。
  • 感谢您对 svanharen 的支持,这是一个很难描述的问题,当您没有真正听到任何声音时,您会想知道您是否是世界上唯一遇到此问题的人 ;)跨度>

标签: asp.net-mvc updatemodel formcollection


【解决方案1】:

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

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

【讨论】:

  • 啊,太好了,正是我所追求的答案类型。感谢您稍微澄清一下,我同意大多数教程和演示让您相信 UpdateModel 是用于更新您的数据库模型的“工具”,我猜不是那么多 - 那么有什么适合我们的吗?或者我想知道将来是否会有。我相信我已经在 EF 中看到了一些用于更新模型的东西,也许 EF 可能比 L2S 更适合 MVC 的 ORM。我也会查看这篇文章,谢谢。
  • 我已经阅读了这篇文章,再次感谢 Levi(高级 MVC 开发人员?),虽然它没有明确我的具体要求,但它确实解释了模型绑定是如何工作的。
  • 我刚刚获得了最棒的体验。
【解决方案2】:

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

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

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

这种不保留记录和数据结构的部分状态的做法使得编写可扩展且行为良好的应用程序变得非常简单(特别是对于浏览器中的后退按钮之类的东西)。

【讨论】:

  • 但是我觉得如果我遵循这个概念,我会有一个更重要的观点,包括很多不必要的冗余数据,特别是没有必要发布,因为它不会被更改。另外不知道如何处理通过 LINQ to SQL 映射的集合和其他关系。
  • ASP.NET MVC 视图比传统的 ASP.NET 轻得多。标记更清晰,您不必与 ViewState 抗衡。你到底有多少数据?它是在线工作申请,还是类似的具有大量表单字段的东西?
  • 恕我直言,我认为您将某些问题称为不是问题。我的页面在一个应用程序中运行,其中包含 100K 数据,并且它们几乎立即加载。
  • 好的,没关系。尺寸。但是我仍然在纠结于以一种形式表示我的整个对象模型的想法,特别是如果说我有 2 个子对象和几个列表,我不确定如何轻松地映射它;一堆描绘整个对象图的隐藏字段?只是看起来很奇怪。
  • 如果我有一个 Employee 详细信息表格,我想在网络上显示以便员工能够更新自己,例如更改他们的紧急联系信息、电话号码等,我绝对希望他们能够更新他们的薪水。完全可以只更新此类记录的一部分,而不需要在 HTTP Posts 中传递整个内容。
【解决方案3】:

对于非列表类型,我非常乐意使用 UpdateModel。我总是很小心地指定 includeProperties 数组(不是因为可能会出现这个问题,而是为了安全——您是否希望用户能够破解表单(非常容易)并提交日期等?)。

这并不是说它不能进一步改进。

此外,在设置要求时要牢记一个实际点:对于接收 POST 的网络服务器,空字段与不存在的字段相同。这意味着,如果 UpdateModel 的设计使其不会“重置”不存在的表单字段(例如日期),则相同的行为将意味着如果用户删除您的日期字段中的文本并发布,它将不会得到更新为空(或 null)。

詹姆斯

【讨论】:

  • 是的,但他们可以检测到表单元素是否存在于数组中,如果它为空,则可以进行区分。
【解决方案4】:

但我仍然在纠结于 代表我的整个对象模型 一个表格,特别是如果说我有 2 子对象和几个列表, 我不确定这会很容易 通过映射;一堆隐藏的 描绘整个对象的字段 地图?只是看起来很奇怪。

为此,您需要研究诸如 SubControllers 和 RenderAction 之类的东西。你可以谷歌这些。我经常使用 RenderAction。它允许我通过自己的控制器方法将小部件注入页面,而无需将单独的数据推送到 ViewData。

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

你是对的。诸如 CreationDate、UpdatedBy 之类的事情应该在控制器中处理(实际上是存储库,如果您使用的是存储库)。到那时,您应该已经拥有视图模型中更新数据库所需的所有字段。

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

【讨论】:

  • 谢谢罗伯。我已经在使用强类型视图模型对象来自定义和包含多个对象集。没问题,感谢您的所有帮助,我认为 NerdDinner 会遇到与他们使用 FormCollection 和 UpdateModel 相同的问题,也许模型不够复杂。我得做一些调查。
  • 我不得不恭敬地不同意。只需创建一个 DTO ViewModel 并将您的数据映射回控制器中的域对象(如果很大,则在单独的映射器类中)。
  • @LuckyLindy -- 这是一种方法,但如果您想要在多个视图中重复某个功能,它就会无休止地重复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
相关资源
最近更新 更多