8
votes

Calling UpdateModel avec une collection de types de données complexes Réinitialisez toutes les valeurs non liées?

Je ne suis pas sûr que ceci est un bogue dans la classe de typefrinder ou quoi. Mais UpdateTemodel ne modifie généralement aucune valeur du modèle, à l'exception de celles qu'il a trouvé une correspondance. Jetez un coup d'œil à ce qui suit:

[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" });
    // ...
}


0 commentaires

3 Réponses :


9
votes

mise à jour: strong> Je suis entré sur le code source MVC (notamment defaultModelbinder Code> Classe) et voici ce que j'ai trouvé:

La classe détermine que nous essayons de lier une collection afin qu'elle appelle la méthode: UpdateCollection (. ..) code> qui crée un modelbindingcontext code> qui comporte un null code> modèle code> propriété. Ensuite, ce contexte est envoyé à la méthode bindcomplexmodel (...) code> qui vérifie la propriété modèle code> pour null code> et crée une nouvelle nouvelle strong> instance du type de modèle si tel est le cas. P>

C'est ce qui provoque la réinitialisation des valeurs. p>

et donc, seules les valeurs qui traversent les données de la chaîne de formulaire / de la chaîne / de la route sont peuplées, le reste reste dans son état initialisé. P>

J'ai pu faire très peu de Modifications apportées à UpdateCollection (...) code> pour corriger ce problème. p>

Voici la méthode avec mes modifications: p>

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;


0 commentaires

1
votes

Vous venez de me donner une idée de creuser dans le code source ASP.NET MVC 2. J'ai eu du mal avec cela pendant deux semaines maintenant. J'ai découvert que votre solution ne fonctionnera pas avec des listes imbriquées. Je mets un point d'arrêt dans la méthode UpdateCollection et il n'est jamais frappé. Il semble que le niveau de racine du modèle doit être une liste de cette méthode à appeler

Ceci est bref le modèle que j'ai..J'ai aussi un niveau de plus de listes génériques, mais il s'agit simplement d'un échantillon rapide. . P>

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


0 commentaires