ASP.NET MVC EF4.7.2表单提交派生类CPU被转为基类Component如何解决
问题原因
ASP.NET MVC 默认模型绑定器会根据Action方法参数的声明类型实例化对象,你Create方法参数声明为Component基类,所以默认只会创建Component实例,仅填充表单中匹配基类的字段,派生类CPU的特有属性会被丢弃,也不会自动实例化派生类对象。你在后端代码中直接传递CPU实例时类型正常,是因为跳过了表单模型绑定的流程,属于手动指定类型的实例化。
解决方案
方案1:自定义多态模型绑定器(推荐,可适配任意数量派生类)
该方案不需要修改现有Action逻辑,仅需要扩展模型绑定逻辑即可支持所有Component派生类的自动识别:
- 在所有派生类的创建视图表单中添加隐藏字段,用来传递当前提交的派生类类型标识:
以CPU视图为例,在Html.BeginForm代码块内新增一行:@Html.Hidden("DerivedTypeName", typeof(CPU).AssemblyQualifiedName) - 自定义继承自
DefaultModelBinder的派生类绑定器:public class ComponentModelBinder : DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) { // 从表单请求中获取派生类类型名 var typeValueResult = bindingContext.ValueProvider.GetValue("DerivedTypeName"); if (typeValueResult == null) return base.CreateModel(controllerContext, bindingContext, modelType); // 解析类型,校验是否属于Component的派生类 var derivedType = Type.GetType(typeValueResult.AttemptedValue); if (derivedType == null || !modelType.IsAssignableFrom(derivedType)) return base.CreateModel(controllerContext, bindingContext, modelType); // 实例化派生类对象,更新绑定上下文的元数据 var modelInstance = Activator.CreateInstance(derivedType); bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => modelInstance, derivedType); return modelInstance; } } - 在项目启动时注册绑定器,打开
Global.asax.cs,在Application_Start方法中添加:ModelBinders.Binders.Add(typeof(Component), new ComponentModelBinder());
配置完成后,提交表单时Create方法接收到的component参数实际类型就是对应的派生类,基类和派生类的属性都会被正确填充,EF可直接识别该对象的派生类型完成保存。
方案2:为每个派生类单独声明Action(实现简单,适合派生类数量少的场景)
不需要修改模型绑定逻辑,为每个派生类新增单独的Post Action,复用现有Create方法的逻辑即可:
// 新增CPU专属提交Action [HttpPost] [Authorize(Roles = "Admin")] public ActionResult CreateCPU(CPU cpu) { return Create(cpu); } // 后续新增其他派生类时只需新增对应Action即可,例如GPU [HttpPost] [Authorize(Roles = "Admin")] public ActionResult CreateGPU(GPU gpu) { return Create(gpu); }
同时修改对应视图的表单提交地址,以CPU视图为例,将Html.BeginForm修改为:
@using (Html.BeginForm("CreateCPU", "Components", FormMethod.Post))
注意事项
如果你的EF使用的是每层次结构一张表(TPH)的继承策略,不需要手动处理Discriminator字段,只要实体对象的实际类型正确,EF会自动填充该字段完成分类存储。
内容的提问来源于stack exchange,提问作者Shaun Falconer
相关产品推荐
相关产品推荐

