【问题标题】:.NET EF 4.7.2 MVC Create method converts child form submission.NET EF 4.7.2 MVC Create 方法转换子表单提交
【发布时间】: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");
    }
}

【问题讨论】:

    标签: c# asp.net-mvc entity-framework inheritance


    【解决方案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) 时它破坏了应用程序
    猜你喜欢
    • 2020-03-20
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多