.NET EF 4.7.2 MVC Create 方法转换子表单提交

Posted

技术标签:

【中文标题】.NET EF 4.7.2 MVC Create 方法转换子表单提交【英文标题】:.NET EF 4.7.2 MVC Create method converts child form submission 【发布时间】:2021-12-19 04:53:31 【问题描述】:

我正在尝试使用 EF 4.7.2 和继承为我的 PC 组件 ASP.NET MVC 应用程序实现创建功能,以便在单个方法中处理所有派生类。

问题在于提交Component_CreateCPU.cshtml 表单会将CPU 的派生类在/Components/Create 操作中转换为其基类Component

我测试了在Index() 中实例化一个新的CPU 对象并将其传递给Create() 方法并保留它的派生类。

有什么方法可以提交视图表单并确保派生类被传入?

模型类:

public class Component : Interfaces.IComponent

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id  get; set; 
    [DisplayName("Name")]
    public string Name  get; set; 
    [DisplayName("Description")]
    public string Description  get; set; 
    [DisplayName("Price")]
    public decimal Price  get; set; 

    public Manufacturer Manufacturer  get; set; 


public class CPU : Component

    [DisplayName("Core Count")]
    public int CoreCount  get; set; 
    [DisplayName("Core Clock")]
    public string CoreClock  get; set; 

创建局部视图

_Component_CreateCPU.cshtml:

@model PCDB.Models.Components.CPU

@using (Html.BeginForm("Create", "Components", FormMethod.Post)) 

    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>CPU</h4>
        <hr />
        @Html.ValidationSummary(true, "", new  @class = "text-danger" )
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new  @class = "control-label col-md-2" )
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new  htmlAttributes = new  @class = "form-control"  )
                @Html.ValidationMessageFor(model => model.Name, "", new  @class = "text-danger" )
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Description, htmlAttributes: new  @class = "control-label col-md-2" )
            <div class="col-md-10">
                @Html.EditorFor(model => model.Description, new  htmlAttributes = new  @class = "form-control"  )
                @Html.ValidationMessageFor(model => model.Description, "", new  @class = "text-danger" )
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Price, htmlAttributes: new  @class = "control-label col-md-2" )
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new  htmlAttributes = new  @class = "form-control"  )
                @Html.ValidationMessageFor(model => model.Price, "", new  @class = "text-danger" )
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CoreCount, htmlAttributes: new  @class = "control-label col-md-2" )
            <div class="col-md-10">
                @Html.EditorFor(model => model.CoreCount, new  htmlAttributes = new  @class = "form-control"  )
                @Html.ValidationMessageFor(model => model.CoreCount, "", new  @class = "text-danger" )
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CoreClock, htmlAttributes: new  @class = "control-label col-md-2" )
            <div class="col-md-10">
                @Html.EditorFor(model => model.CoreClock, new  htmlAttributes = new  @class = "form-control"  )
                @Html.ValidationMessageFor(model => model.CoreClock, "", new  @class = "text-danger" )
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>


<div>
    @Html.ActionLink("Back to List", "Index")
</div>

ComponentsController:

public class ComponentsController : Controller

    private readonly IComponentRepository<Component> _componentRepository;
    
    public ComponentsController()
    
        _componentRepository = new ComponentsRepository<Component>();

    

    public ActionResult Index()
    
        return View(_componentRepository.GetAll());
    

    [Authorize(Roles = "Admin")]
    public ActionResult Create()
    
        return View(new ComponentCreateViewModel());
    

    [Authorize(Roles = "Admin")]
    [HttpPost]
    public ActionResult Create(Component component)
    
        if (ModelState.IsValid)
        
            _componentRepository.Insert(component);
            _componentRepository.Save();
        

        return Content("Success");
    

【问题讨论】:

【参考方案1】:

当您将表单发布到控制器时,浏览器不会序列化实体,它只是传递与您的控制器方法接受的对象的属性相结合的字段,或者其中参数的字段名称控制器方法。

因此,在您的情况下,您的控制器需要一个基类组件,这就是它将接收的全部内容,而不是 CPU 或其他子类的实例。 (虽然可能值得测试如果 Component 是 abstract 会发生什么)我的建议是实现每个子类的方法。如果有适用于组件级别的位,则在接收子类后将这些位通过传递给通用方法:

    [Authorize(Roles = "Admin")]
    [HttpPost]
    public ActionResult CreateCPU(CPU cpu)
    
        if (ModelState.IsValid)
        
            _componentRepository.Insert(cpu);
            _componentRepository.Save();
        

        return Content("Success");
    

ComponentRepository 仍然可以接受 Insert(Component),前提是它最终可以确保引用正确的 DbSet,或者 DbContext.Entity&lt;T&gt; 将解析传入的 CPU 与其他组件。

【讨论】:

感谢您的回复 - 为每个子类型实现一个方法似乎是最好的方法!出于好奇,我尝试将Component 设为抽象类,但在尝试将CPU 提交给Create(Component component) 时它破坏了应用程序

以上是关于.NET EF 4.7.2 MVC Create 方法转换子表单提交的主要内容,如果未能解决你的问题,请参考以下文章

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(55)-工作流设计-表单布局

MVC5+EF6简单实例---以原有SQLServer数据库两表联合查询为例

Microsoft 'Identity Platform' 是不是(轻松)与'(ASP.NET) Identity Framework' - MVC5 & .NET 4.7.2 集成?

Asp.Net MVC EF各版本区别

如何在 ScriptBundle for .NET MVC (4.7.2) 应用程序中包含 SRI 哈希?

Asp.Net MVC EF各版本区别