一个例子,如果我有一个名为Order的类,其中一个字段引用一个Customer,然后一个Order表单带有一个下拉列表(<%= Html.DropDownListFor(e => e.Customer.ID,new) SelectList(...))%>)用于设置Customer,模型绑定器将创建一个仅设置了ID的空Customer。这适用于NHibernate,但是当验证添加到Customer类的某些字段时,模型绑定器会说这些字段是必需的。如何防止模型绑定器验证这些引用?
谢谢!
答案 0 :(得分:0)
年老的问题,但我想我总是回答后人的问题。在这种情况下,您需要一个自定义模型绑定程序来拦截该属性,然后再尝试绑定它。默认模型绑定器将递归尝试使用其自定义绑定器绑定属性,如果未设置则默认绑定属性。
您在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);
}
}
请注意,在View中我们为model.foo.bar创建DropDownList。 Id 。在模型绑定器中,确保将其添加到模型名称中。您可以将其从两者中删除,但DropDownListFor在找到所选值时遇到一些问题,而无需在您发送的SelectList中预先选择它。
最后,回到控制器中,确保在数据库上下文中附加此属性(如果您使用的是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);
}