복잡한 데이터 유형 모음으로 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에서 이름 및 연령 속성을 할당하고 인수 목록 <>에 넣습니다.이 속성의 나머지 부분을 기본 초기 값 (예 : ID = 0)으로 설정하게하십시오. 그래서 여기서 무슨 일이 일어나고 있습니까?

도움이 되었습니까?

해결책

업데이트:MVC 소스 코드 (특히 DefaultModelBinder 수업) 그리고 여기에 내가 찾은 내용은 다음과 같습니다.

수업은 컬렉션을 바인딩하려고한다고 결정하여 메소드를 호출합니다. UpdateCollection(...) 내부를 만듭니다 ModelBindingContext 그게 a null Model 재산. 그 후, 그 컨텍스트는 메소드로 전송됩니다 BindComplexModel(...) 확인합니다 Model 재산 null 그리고 a 새로운 이 경우 모델 유형의 인스턴스입니다.

그것이 값을 재설정하는 원인입니다.

따라서 양식/쿼리 문자열/경로 데이터를 통해 오는 값 만 채워지고 나머지는 초기 상태로 유지됩니다.

나는 거의 변경할 수 없었습니다 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;

}

다른 팁

Rudi Breedenraed는 방금 우수한 글을 썼습니다 게시하다 이 문제와 매우 유용한 솔루션을 설명합니다. 그는 DefaultModelBinder를 무시한 다음 컬렉션을 통해 업데이트 할 때 실제로 기본 MVC 동작과 같이 새로운 항목을 작성하는 대신 항목을 업데이트합니다. 이를 통해 updateModel () 및 tryupdatemodel () 동작은 루트 모델과 컬렉션과 일치합니다.

방금 ASP.NET MVC 2 소스 코드를 파헤칠 아이디어를주었습니다. 나는 지금 2 주 동안 이것으로 어려움을 겪고있다. 귀하의 솔루션이 중첩 된 목록에서 작동하지 않는다는 것을 알았습니다. 나는 updateCollection 방법에 중단 점을 넣고 결코 치지 않습니다. 이 방법을 호출하려면 모델의 루트 레벨이 목록이어야하는 것 같습니다.

이것은 내가 가지고있는 모델입니다. 나는 또한 일반 목록의 레벨이 하나 더 있지만 이것은 빠른 샘플입니다.

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

나는 무슨 일이 일어나고 있는지 알아 내기 위해 더 깊이 파고 들어야 할 것 같아요.

업데이트 : ASP.NET MVC 2에서 UpdateCollection이 여전히 호출되지만 위의 수정 문제는 이와 관련이 있습니다. 여기

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top