ASP.NET MVC 中 UpdateModel 的正确行为是什么?
我很想知道你们认为 ASP.NET MVC 中的 UpdateModel
方法应该被视为“正确的行为”。
我在这里问的原因也许是,如果这个功能是“设计”的,有人可以澄清为什么它是这样的,也许是一种以不同的方式调用它以实现所需功能的方法,我想这将是90 % 的人希望这个能起作用?
本质上,我的抱怨在于 UpdateModel
中绑定过程的行为。
假设您希望通过简单的 Save
操作方法更新表单,表单上的数据字段反映数据库中的模型,最初要保存请求,我们可能会从以下位置获取现有模型DB,然后更新已更改的相关字段,通过 FormCollection
发送,然后通过 UpdateModel
更新到我们现有的模型。 此功能,但似乎此数据库填充对象上的任何现有属性都被“重置”; 我的意思是,它们被设置为 null 或初始化默认值,就像它是一个全新的对象一样,除了那些与 FormCollection
中的对象明显匹配的对象。
这是一个问题,因为对象上存在但不一定存在于表单上的任何现有属性(例如任何子集合或对象、日期或任何非面向 UI 的字段)都是空的,留下了一半填充的、更多的内容。或更少不可用的对象,由于所有丢失的数据(包括可能的 ID 堆栈)现在设置为 0,因此无法保存到数据库。
我认为这不是理想的行为,并且 UpdateModel
应该只更新它在 FormCollection
中找到属性匹配的属性。 这意味着您的所有现有属性都将保持不变,但您的更新将被设置。 然而,从到目前为止所推断的情况来看,显然情况并非如此 - 它似乎实例化了对象的全新副本,更新表单中的属性,然后返回新对象。
最后,要考虑到这是一个多大的负担,真正绕过它来保存半复杂表单并保留所有现有对象数据的唯一方法是手动结合 each 属性与相应的表单属性一起绝对保证仅更新表单中存在的属性。
我想,
- 那些同意这是有意为之的人,我的形式结合方式是最好的方式吗?
- 或者,您是如何解决这个问题的?
请随意提出您对这些人的想法,谢谢。
这是另一个遭受此问题困扰的人的例子:
使用复杂数据类型的集合重置所有非绑定值?
I am interested to know what you guys feel should be deemed "correct behaviour" in terms of the UpdateModel
method in ASP.NET MVC.
The reason I ask here is perhaps if this functionality is "by design" somebody could clarify as to why it is the way it is, and perhaps a way to call it differently to achieve desired functionality, which I would imagine would be the way 90% of folk would want this to work?
In essence, my gripe lies with the behaviour of the binding process within UpdateModel
.
Supposing you wish to update a form via a simple Save
action method for which the data fields on the form reflects a model in your database, initially to go about saving the request, we might get the existing model from the DB, and then update relevant fields which which were changed, sent via FormCollection
and then updated by UpdateModel
to our existing model. This functions, however it appears any of the existing properties on this DB-populated object are being "reset"; and by that I mean, are being set to null or initialisation defaults just as if it was a brand new object, except for obviously those which match those in the FormCollection
.
This is a problem because any existing properties which exist on the object, but not necessarily exist on the form, such as any child collections or objects, dates or any non-UI facing fields are empty, leaving you with a half-populated, more or less unusable object which can't be saved to the DB because of all the missing data including probably a stack of ID's now set to 0.
I believe this is not desirable behaviour, and UpdateModel
should only update properties where it finds a property match in FormCollection
. This would mean all your existing properties would be untouched, but your updates would be set. However, from what has been deduced so far, obviously this is not the case - it appears it instantiates a brand new copy of the object updates the properties from the form, then returns the new object.
Finally, to put it in perspective of how much of a burden this is, the only way really around it to save a half-complex form and keep all your existing object data is to manually marry up each property with the corresponding form property to absolutely guarantee only properties that exist in the form are being updated.
I guess,
- Those who agree this is by design, is my approach of form marrying the best way?
- Or, how have you tackled this in this?
Please feel free to offer your thoughts on this guys, Thanks.
Here is another instance of somebody suffering from this problem:
Calling UpdateModel with a collection of complex data types reset all non-bound values?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我相信您对 UpdateModel 行为的看法是正确的。
但是,ASP.NET MVC 遵循“往返”模型,这意味着您的表单应该已经包含生成完整记录所需的所有字段,因为您将所有字段的值推送到视图中,或者您要求用户提供所有字段。
这个往返的概念非常重要。 请记住,在真正的 MVC 模型中没有状态的概念。 您从数据库表中检索数据,将该数据推送到视图,将数据显示给用户,然后程序停止。 用户编辑数据,单击发布按钮,视图将数据发布到控制器方法,数据保存到数据库中,然后程序停止。 一项操作与另一项操作之间根本不存在依赖关系。
这种不保留记录和数据结构的部分状态的做法使得编写可扩展且行为良好的应用程序变得非常简单(特别是在浏览器中的后退按钮等方面)。
I believe you are right about the behavior of UpdateModel.
However, ASP.NET MVC follows a "round-trip" model, meaning that your form should already contain all of the fields it needs to produce a complete record, either because you pushed values for all of the fields into the view, or you are asking for all of the fields from the user.
This round-trip concept is very important. Remember that in a true MVC model there is no concept of state. You retrieve data from a database table, push this data to a view, the data is displayed to the user, and the program stops. The user edits the data, clicks your post button, the view posts data to a controller method, the data is saved into the database, and the program stops. There are no dependencies at all from one operation to the next.
This practice of not keeping partial state of records and data structures makes it very straightforward to write applications that scale well, and are well-behaved (particularly with respect to things like the back button in the browser).
对于非列表类型,我非常乐意使用 UpdateModel。 我总是小心地指定 includeProperties 数组(不是因为可能出现此问题,而是为了安全 - 您是否希望用户能够破解表单(非常简单)并提交日期等?)。
这并不是说它不能进一步改进。
另外,在设置要求时要记住一个实用的要点:对于接收 POST 的网络服务器,空字段与不存在的字段相同。 这意味着,如果 UpdateModel 的设计不会“重置”不存在的表单字段(例如日期),则相同的行为意味着如果用户删除日期字段和帖子中的文本,则它不会更新为空(或 null)。
詹姆士
I use UpdateModel quite happily for non-list types. I'm always careful to specify the includeProperties array (not because of the potential for this problem, but for security -- do you want the user to be able to hack the form (very easy) and submit dates, etc?).
That's not to say it can't be improved further.
Also, a practical point to keep in mind when setting the requirements: to a webserver receiving a POST, an empty field is the same as a non-existent field. That means that if UpdateModel were designed such that it did not "reset" non-existent form fields (such as date), the same behavior would mean that if the user removes the text in your date field and posts, it would not get updated with empty (or null).
james
为此,您需要研究诸如 SubControllers 和 RenderAction 之类的东西。 你可以谷歌那些。 我经常使用 RenderAction。 它允许我从其自己的控制器方法将小部件注入到页面中,而无需将单独的数据推送到 ViewData 中。
你是对的。 像 CreationDate、UpdatedBy 这样的事情应该在控制器(实际上是存储库,如果您使用存储库)中处理。 到那时,您应该已经拥有视图模型中更新数据库所需的所有字段。
您可能需要使用“强类型视图模型”对象。 如果您不确定或不确定,请查看此页面:http://nerddinnerbook.s3。 amazonaws.com/Part6.htm
For this, you need to look into things like SubControllers and RenderAction. You can Google those. I use RenderAction a lot. It allows me to inject a widget into a page from its own controller method, without having to push separate data into the ViewData.
You are right about that. Things like CreationDate, UpdatedBy should be handled in the Controller (actually the repository, if you are using repositories). By that time, you should already have all of the fields you need from the view model to update your database.
You may need to use "strongly-typed view model" objects. If you are not, or are not sure, review this page: http://nerddinnerbook.s3.amazonaws.com/Part6.htm
您使用 UpdateModel() 遇到的行为听起来像是列表绑定,在这种情况下 UpdateModel() 将清除列表的内容并重新填充它。 有关此问题的讨论,请参阅 Hanselman 的博客。 如果您要更新单个对象,UpdateModel() 将更新该单个对象,保留没有相应表单值的属性。
其中许多问题都归结为 UpdateModel() 实际上是为了根据表单输入重新填充视图模型(而不是域模型)。 (我稍微简化了一下,视图模型只是控制器和视图之间的契约,而域模型可能是 LINQ2SQL 或 EF 模型对象。)所有 MVC 教程和演示都显示 UpdateModel() 是用于数据库对象,我认为这是不幸的,因为它对模型绑定的预期目的有些误导。 Robert 的帖子更能说明 UpdateModel() 的实际意图。
The behavior you're experiencing with UpdateModel() sounds like you're list binding, in which case UpdateModel() will blow away the contents of the list and repopulate it. See Hanselman's blog for a discussion on this. If you're updating a single object, UpdateModel() will update that individual object, leaving properties that don't have a corresponding form value as-is.
Many of these problems boil down to that UpdateModel() is really meant to repopulate view models - not domain models - based on form input. (I'm slightly simplifying things by saying that a view model is just a contract between a controller and the view, while your domain model might be a LINQ2SQL or EF model object.) All of the MVC tutorials and demos show UpdateModel() being used against database objects, which I feel is unfortunate since it's somewhat misleading as to the intended purpose of model binding. Robert's post is more indicative of the actual intent of UpdateModel().