net mvc framework first example asp asp.net-mvc model-binding updatemodel

asp.net mvc - mvc - ¿Llamar a UpdateModel con una colección de tipos de datos complejos restablecer todos los valores no enlazados?



mvc model example (3)

No estoy seguro de si esto es un error en la clase DefaultModelBinder o qué. Pero UpdateModel por lo general no cambia ningún valor del modelo, excepto los que encontró una coincidencia. Eche un vistazo a lo siguiente:

[AcceptVerbs(HttpVerbs.Post)] public ViewResult Edit(List<int> Ids) { // Load list of persons from the database List<Person> people = GetFromDatabase(Ids); // shouldn''t this update only the Name & Age properties of each Person object // in the collection and leave the rest of the properties (e.g. Id, Address) // with their original value (whatever they were when retrieved from the db) UpdateModel(people, "myPersonPrefix", new string[] { "Name", "Age" }); // ... }

Lo que ocurre es que UpdateModel crea nuevos objetos Person, asigna sus propiedades Name y Age desde ValueProvider y los pone en el argumento List <>, que establece el resto de las propiedades en su valor inicial predeterminado (por ejemplo, Id = 0) entonces, ¿qué es? pasando aquí?


ACTUALIZACIÓN: pasé por el código fuente de DefaultModelBinder (particularmente la clase DefaultModelBinder ) y aquí está lo que encontré:

La clase determina que estamos intentando vincular una colección para que llame al método: UpdateCollection(...) que crea un ModelBindingContext interno que tiene una propiedad de Model null . Después, ese contexto se envía al método BindComplexModel(...) que verifica la propiedad Model para null y crea una nueva instancia del tipo de modelo si ese es el caso.

Eso es lo que hace que los valores se restablezcan.

Por lo tanto, solo se rellenan los valores que se obtienen a través de la cadena de formulario / consulta / datos de ruta, el resto permanece en su estado inicializado.

Pude hacer muy pocos cambios en UpdateCollection(...) para solucionar este problema.

Este es el método con mis cambios:

internal object UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType) { IModelBinder elementBinder = Binders.GetBinder(elementType); // build up a list of items from the request List<object> modelList = new List<object>(); for (int currentIndex = 0; ; currentIndex++) { string subIndexKey = CreateSubIndexName(bindingContext.ModelName, currentIndex); if (!DictionaryHelpers.DoesAnyKeyHavePrefix(bindingContext.ValueProvider, subIndexKey)) { // we ran out of elements to pull break; } // ********************************************************** // The DefaultModelBinder shouldn''t always create a new // instance of elementType in the collection we are updating here. // If an instance already exists, then we should update it, not create a new one. // ********************************************************** IList containerModel = bindingContext.Model as IList; object elementModel = null; if (containerModel != null && currentIndex < containerModel.Count) { elementModel = containerModel[currentIndex]; } //***************************************************** ModelBindingContext innerContext = new ModelBindingContext() { Model = elementModel, // assign the Model property ModelName = subIndexKey, ModelState = bindingContext.ModelState, ModelType = elementType, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; object thisElement = elementBinder.BindModel(controllerContext, innerContext); // we need to merge model errors up VerifyValueUsability(controllerContext, bindingContext.ModelState, subIndexKey, elementType, thisElement); modelList.Add(thisElement); } // if there weren''t any elements at all in the request, just return if (modelList.Count == 0) { return null; } // replace the original collection object collection = bindingContext.Model; CollectionHelpers.ReplaceCollection(elementType, collection, modelList); return collection;

}


Rudi Breedenraed acaba de escribir una excelente publicación describiendo este problema y una solución muy útil. Reemplaza a DefaultModelBinder y luego cuando se encuentra con una colección para actualizar, realmente actualiza el elemento en lugar de crearlo como el comportamiento predeterminado de MVC. Con esto, el comportamiento de UpdateModel () y TryUpdateModel () es consistente tanto con el modelo de raíz como con cualquier colección.


Me acabas de dar una idea para profundizar en el código fuente de ASP.NET MVC 2. He estado luchando con esto durante dos semanas. Descubrí que su solución no funcionará con listas anidadas. Puse un punto de interrupción en el método UpdateCollection, y nunca se golpea. Parece que el nivel de raíz del modelo debe ser una lista para que se llame este método

Este es, en definitiva, el modelo que tengo ... También tengo un nivel más de listas genéricas, pero esto es solo una muestra rápida.

public class Borrowers { public string FirstName{get;set;} public string LastName{get;set;} public List<Address> Addresses{get;set;} }

Supongo que necesitaré profundizar para descubrir qué está pasando.

ACTUALIZACIÓN: UpdateCollection aún se llama en asp.net mvc 2, pero el problema con la corrección anterior está relacionado con esto AQUÍ