8

これが 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 から割り当て、それらを引数 List<> に配置すると、残りのプロパティがデフォルトの初期値 (例: Id = 0) に設定されます。ここで起こっている?

4

3 に答える 3

9

更新: mvc ソース コード (特にDefaultModelBinderクラス) を調べたところ、次のような結果が得られました。

クラスは、コレクションをバインドしようとしていると判断し、メソッドを呼び出します:プロパティを持つUpdateCollection(...)インナーを作成します。その後、そのコンテキストがメソッドに送信され、プロパティがチェックされ、モデル タイプの新しいインスタンスが作成されます (該当する場合)。ModelBindingContextnull ModelBindComplexModel(...)Modelnull

それが値がリセットされる原因です。

そのため、フォーム/クエリ文字列/ルート データからの値のみが入力され、残りは初期化された状態のままです。

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;

}

于 2009-07-30T19:26:36.147 に答える
4

Rudi Breedenraedは、この問題と非常に役立つ解決策を説明する優れた投稿を書きました。彼はDefaultModelBinderをオーバーライドし、更新するコレクションに出くわすと、デフォルトのMVC動作のようにアイテムを新しく作成するのではなく、実際にアイテムを更新します。これにより、UpdateModel()およびTryUpdateModel()の動作は、ルートモデルとすべてのコレクションの両方と一貫性があります。

于 2010-02-25T21:49:49.813 に答える
1

あなたは、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 で呼び出されますが、上記の修正の問題はこれに関連していますHERE

于 2010-02-11T15:58:29.160 に答える