What is correct behaviour of UpdateModel in ASP.NE

2019-02-01 00:35发布

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,

  1. Those who agree this is by design, is my approach of form marrying the best way?
  2. 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?

4条回答
戒情不戒烟
2楼-- · 2019-02-01 00:53

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).

查看更多
可以哭但决不认输i
3楼-- · 2019-02-01 01:02

But I still struggle with the idea of representing my entire object model in a form, especially if say I had 2 child objects and a couple of lists, I'm not sure how this would easily be mapped through; A stack of hidden fields depicting the entire object map? Just seems odd.

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.

I don't think one should have to soely guarantee any data you wish to update to your DB model, should exist entirely on the form. I don't think I have one db table which could facilitate this, consider a "creation date" for example, or "updated date", I don't think it would be ideal to store this in a hidden field on the form.

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

查看更多
smile是对你的礼貌
4楼-- · 2019-02-01 01:10

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().

查看更多
成全新的幸福
5楼-- · 2019-02-01 01:13

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

查看更多
登录 后发表回答