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

.NET EF 4.7.2 MVC Create method converts child form submission

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

问题是提交 Component_CreateCPU.cshtml 表单将 CPU 的派生 class 转换为其在 /Components/Create 中的基础 class Component动作。

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

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

型号classes:

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");
    }
}

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

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

    [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<T> 将解析传入的 CPU 与其他组件.