هل يؤدي استدعاء UpdateModel مع مجموعة من أنواع البيانات المعقدة إلى إعادة تعيين كافة القيم غير المرتبطة؟

StackOverflow https://stackoverflow.com/questions/1207991

سؤال

لست متأكدًا مما إذا كان هذا خطأ في فئة 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 جديد تقوم كائنات الأشخاص بتعيين خصائص الاسم والعمر الخاصة بها من ValueProvider ووضعها في الوسيطة List<>، مما يجعل بقية الخصائص مضبوطة على قيمتها الأولية الافتراضية (على سبيل المثال.معرف = 0) إذن ما الذي يحدث هنا؟

هل كانت مفيدة؟

المحلول

تحديث:لقد تدخلت عبر كود مصدر mvc (خاصة DefaultModelBinder class) وهذا ما وجدته:

يحدد الفصل أننا نحاول ربط مجموعة لذلك يستدعي الطريقة: 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، ولكن مشكلة الإصلاح أعلاه مرتبطة بهذا هنا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top