17

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

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

本质上,我的抱怨在于UpdateModel.

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

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

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

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

我猜,

  1. 那些同意这是设计使然的人,我的形式结合是最好的方式吗?
  2. 或者,你是如何解决这个问题的?

请随时提供您对这些人的想法,谢谢。

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

4

4 回答 4

15

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

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

于 2009-08-07T04:07:34.097 回答
5

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

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

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

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

于 2009-08-07T03:47:39.017 回答
2

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

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

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

詹姆士

于 2009-08-07T10:48:55.657 回答
2

但是我仍然在纠结于以一种形式表示我的整个对象模型的想法,特别是如果说我有 2 个子对象和几个列表,我不确定如何轻松地映射它;一堆描绘整个对象图的隐藏字段?只是看起来很奇怪。

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

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

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

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

于 2009-08-07T22:58:57.163 回答