Вызов UpdateModel с набором сложных типов данных сбрасывает все несвязанные значения?
-
05-07-2019 - |
Вопрос
Я не уверен, является ли это ошибкой в классе DefaultModelBinder или что-то в этом роде.Но UpdateModel обычно не изменяет никаких значений модели, кроме тех, которым она нашла соответствие.Взгляните на следующее:
[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" });
// ...
}
Что происходит, так это создание UpdateModel новое Объекты Person присваивают им свойства Name & Age из ValueProvider и помещают их в список аргументов<>, что приводит к тому, что остальным свойствам присваивается начальное значение по умолчанию (напримерId = 0) так что же здесь происходит?
Решение
Обновить:
Я прошелся по исходному коду mvc (в частности DefaultModelBinder
класс) и вот что я нашел:
Класс определяет, что мы пытаемся связать коллекцию, поэтому он вызывает метод: UpdateCollection(...)
который создает внутреннюю ModelBindingContext
это имеет null
Model
собственность.После этого этот контекст отправляется методу BindComplexModel(...)
который проверяет Model
собственность для null
и создает новое экземпляр типа модели, если это так.
Это то, что приводит к сбросу значений.
Таким образом, заполняются только те значения, которые поступают через форму / строку запроса / данные маршрута, остальное остается в своем инициализированном состоянии.
Мне удалось внести очень мало изменений в UpdateCollection(...)
чтобы устранить эту проблему.
Вот метод с моими изменениями:
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;
}
Другие советы
Руди Бриденред только что написал отличную Публикация описание этой проблемы и очень полезное решение.Он переопределяет DefaultModelBinder, а затем, когда он сталкивается с коллекцией для обновления, он фактически обновляет элемент вместо того, чтобы создавать его новым, как поведение MVC по умолчанию.При этом поведение UpdateModel() и TryUpdateModel() согласуется как с корневой моделью, так и с любыми коллекциями.
Ты только что подал мне идею порыться в ASP.NET в MVC 2 исходный код.Я борюсь с этим уже две недели.Я обнаружил, что ваше решение не будет работать с вложенными списками.Я устанавливаю точку останова в методе UpdateCollection , и она никогда не попадает.Похоже, что корневой уровень модели должен быть списком для вызова этого метода
Это вкратце та модель, которая у меня есть..У меня также есть еще один уровень общих списков, но это всего лишь краткий пример..
public class Borrowers
{
public string FirstName{get;set;}
public string LastName{get;set;}
public List<Address> Addresses{get;set;}
}
Я предполагаю, что мне нужно копнуть глубже, чтобы выяснить, что происходит.
Обновить:UpdateCollection по-прежнему вызывается в asp.net mvc 2, но проблема с приведенным выше исправлением связана с этим ЗДЕСЬ