複雑なデータ型のコレクションで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は new Personオブジェクトを作成し、名前を割り当てます<!> amp; ValueProviderのプロパティをエージングし、それらを引数List <!> lt; <!> gt;に入れます。これにより、残りのプロパティがデフォルトの初期値に設定されます(例:Id = 0) ここで何が起こっているのですか?
解決
更新:
私はmvcソースコード(特にDefaultModelBinder
クラス)をステップスルーしましたが、ここに私が見つけたものがあります:
クラスは、コレクションをバインドしようとしているので、メソッドを呼び出します:UpdateCollection(...)
は、ModelBindingContext
null
プロパティを持つ内部Model
を作成します。その後、そのコンテキストはメソッドBindComplexModel(...)
に送信され、<=>プロパティで<=>がチェックされ、モデルタイプの new インスタンスが作成されます(その場合)。
それが値をリセットする原因です。
したがって、フォーム/クエリ文字列/ルートデータを介して入力される値のみが入力され、残りは初期化された状態のままになります。
この問題を修正するために、<=>にほとんど変更を加えることができませんでした。
変更したメソッドは次のとおりです。
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;
}
他のヒント
ASP.NET MVC 2のソースコードを掘り下げるというアイデアを与えてくれました。 私はこれに2週間苦労しています。あなたのソリューションはネストされたリストでは動作しないことがわかりました。 UpdateCollectionメソッドにブレークポイントを設定しましたが、ヒットしません。モデルのルートレベルは、このメソッドを呼び出すためのリストである必要があるようです
これは、私が持っているモデルです。もう1つのレベルの汎用リストもありますが、これは簡単なサンプルです。
public class Borrowers
{
public string FirstName{get;set;}
public string LastName{get;set;}
public List<Address> Addresses{get;set;}
}
どうなっているのかを知るために、さらに深く掘り下げる必要があると思います。
更新: UpdateCollectionはasp.net mvc 2で引き続き呼び出されますが、上記の修正の問題はこのここ