Старый вопрос, но я решил, что в любом случае отвечу за потомство.В этой ситуации вам необходим пользовательский механизм связывания, чтобы перехватить это свойство, прежде чем оно попытается его связать.Привязка модели по умолчанию будет рекурсивно пытаться связать свойства, используя их пользовательское связывание или заданное по умолчанию, если оно не установлено.
Переопределение, которое вы ищете в DefaultModelBinder, - это GetPropertyValue.Это вызывается для всех свойств в модели, и по умолчанию вызывается DefaultModelBinder.BindModel - точка входа во весь процесс.
Упрощенная модель:
public class Organization
{
public int Id { get; set; }
[Required]
public OrganizationType Type { get; set; }
}
public class OrganizationType
{
public int Id { get; set; }
[Required, MaxLength(30)]
public string Name { get; set; }
}
Представление:
<div class="editor-label">
@Html.ErrorLabelFor(m => m.Organization.Type)
</div>
<div class="editor-field">
@Html.DropDownListFor(m => m.Organization.Type.Id, Model.OrganizationTypes, "-- Type")
</div>
Связыватель модели:
public class OrganizationModelBinder : DefaultModelBinder
{
protected override object GetPropertyValue(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
System.ComponentModel.PropertyDescriptor propertyDescriptor,
IModelBinder propertyBinder)
{
if (propertyDescriptor.PropertyType == typeof(OrganizationType))
{
var idResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Id");
if (idResult == null || string.IsNullOrEmpty(idResult.AttemptedValue))
{
return null;
}
var id = (int)idResult.ConvertTo(typeof(int));
// Can validate the id against your database at this point if needed...
// Here we just create a stub object, skipping the model binding and
// validation on OrganizationType
return new OrganizationType { Id = id };
}
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
}
Обратите внимание, что в представлении мы создаем DropDownListFor для модели.foo.bar. Id .В связывателе модели убедитесь, что это также добавлено к названию модели.Вы можете отключить его от обоих, но тогда у DropDownListFor есть несколько проблем с поиском выбранного значения без предварительного выбора его в списке выбора, который вы отправляете.
Наконец, вернувшись в контроллер, обязательно присоедините это свойство.в контексте вашей базы данных (если вы используете Entity Framework, другие могут работать по-другому).В противном случае он не отслеживается, и контекст попытается добавить его при сохранении.
Контроллер:
public ActionResult Create(Organization organization)
{
if (ModelState.IsValid)
{
_context.OrganizationTypes.Attach(organization.Type);
_context.Organizations.Add(organization);
_context.SaveChanges();
return RedirectToAction("Index");
}
// Build up view model...
return View(viewModel);
}