是否可以将我的模型上的外键关系绑定(bind)到表单输入?
假设我在 Car
之间存在一对多关系和 Manufacturer
.我想要一个更新表格Car
包括用于设置 Manufacturer
的选择输入.我希望能够使用内置模型绑定(bind)来做到这一点,但我开始认为我必须自己做。
我的操作方法签名如下所示:
public JsonResult Save(int id, [Bind(Include="Name, Description, Manufacturer")]Car car)
表单发布值名称、描述和制造商,其中制造商是
int
类型的主键.名称和描述设置正确,但制造商设置不正确,这是有道理的,因为模型绑定(bind)器不知道 PK 字段是什么。这是否意味着我必须编写自定义 IModelBinder
那它知道吗?我不确定这将如何工作,因为我的数据访问存储库是通过每个 Controller
上的 IoC 容器加载的。构造函数。
最佳答案
这是我的看法 - 这是一个自定义模型绑定(bind)器,当要求 GetPropertyValue 时,它会查看该属性是否是我的模型程序集中的一个对象,并且在我的 NInject IKernel 中注册了一个 IRepository<>。如果它可以从 Ninject 获得 IRepository,它会使用它来检索外键对象。
public class ForeignKeyModelBinder : System.Web.Mvc.DefaultModelBinder
{
private IKernel serviceLocator;
public ForeignKeyModelBinder( IKernel serviceLocator )
{
Check.Require( serviceLocator, "IKernel is required" );
this.serviceLocator = serviceLocator;
}
/// <summary>
/// if the property type being asked for has a IRepository registered in the service locator,
/// use that to retrieve the instance. if not, use the default behavior.
/// </summary>
protected override object GetPropertyValue( ControllerContext controllerContext, ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder )
{
var submittedValue = bindingContext.ValueProvider.GetValue( bindingContext.ModelName );
if ( submittedValue == null )
{
string fullPropertyKey = CreateSubPropertyName( bindingContext.ModelName, "Id" );
submittedValue = bindingContext.ValueProvider.GetValue( fullPropertyKey );
}
if ( submittedValue != null )
{
var value = TryGetFromRepository( submittedValue.AttemptedValue, propertyDescriptor.PropertyType );
if ( value != null )
return value;
}
return base.GetPropertyValue( controllerContext, bindingContext, propertyDescriptor, propertyBinder );
}
protected override object CreateModel( ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType )
{
string fullPropertyKey = CreateSubPropertyName( bindingContext.ModelName, "Id" );
var submittedValue = bindingContext.ValueProvider.GetValue( fullPropertyKey );
if ( submittedValue != null )
{
var value = TryGetFromRepository( submittedValue.AttemptedValue, modelType );
if ( value != null )
return value;
}
return base.CreateModel( controllerContext, bindingContext, modelType );
}
private object TryGetFromRepository( string key, Type propertyType )
{
if ( CheckRepository( propertyType ) && !string.IsNullOrEmpty( key ) )
{
Type genericRepositoryType = typeof( IRepository<> );
Type specificRepositoryType = genericRepositoryType.MakeGenericType( propertyType );
var repository = serviceLocator.TryGet( specificRepositoryType );
int id = 0;
#if DEBUG
Check.Require( repository, "{0} is not available for use in binding".FormatWith( specificRepositoryType.FullName ) );
#endif
if ( repository != null && Int32.TryParse( key, out id ) )
{
return repository.InvokeMethod( "GetById", id );
}
}
return null;
}
/// <summary>
/// perform simple check to see if we should even bother looking for a repository
/// </summary>
private bool CheckRepository( Type propertyType )
{
return propertyType.HasInterface<IModelObject>();
}
}
您显然可以用 Ninject 代替您的 DI 容器和您自己的存储库类型。
关于asp.net-mvc - ASP.NET MVC 模型绑定(bind)外键关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/662651/