加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – ASP.NET MVC模型绑定外键关系

发布时间:2020-12-16 04:10:06 所属栏目:asp.Net 来源:网络整理
导读:是否可以将模型上的外键关系绑定到表单输入? 说我在Car和Manufacturer之间有一对多的关系.我想要一个更新Car的表单,其中包含用于设置Manufacturer的选择输入.我希望能够使用内置的模型绑定来做到这一点,但我开始认为我必须自己做. 我的动作方法签名如下所示
是否可以将模型上的外键关系绑定到表单输入?

说我在Car和Manufacturer之间有一对多的关系.我想要一个更新Car的表单,其中包含用于设置Manufacturer的选择输入.我希望能够使用内置的模型绑定来做到这一点,但我开始认为我必须自己做.

我的动作方法签名如下所示:

public JsonResult Save(int id,[Bind(Include="Name,Description,Manufacturer")]Car car)

表单发布值Name,Description和Manufacturer,其中Manufacturer是int类型的主键.名称和描述设置正确,但不是制造商,这是有道理的,因为模型绑定器不知道PK字段是什么.这是否意味着我必须编写一个它知道这个的自定义IModelBinder?我不确定这是如何工作的,因为我的数据访问存储库是通过每个Controller构造函数上的IoC容器加载的.

解决方法

这是我的看法 – 这是一个自定义模型绑定器,当被问到GetPropertyValue时,查看属性是否是我的模型程序集中的对象,并且具有IRepository<>在我的NInject IKernel中注册.如果它可以从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,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,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容器和您自己的存储库类型.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读