C# ViewModel DropDownList和HTTP Post控制器

C# ViewModel DropDownList和HTTP Post控制器,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我的创建操作与Post Controller有一些问题。下面是我的模型,圆形,材质,材质形状,原材料。我的主要目标是向数据库中添加Round对象 public class Material { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } [Required] [Display(Name="Material")] pu

我的创建操作与Post Controller有一些问题。下面是我的模型,圆形,材质,材质形状,原材料。我的主要目标是向数据库中添加Round对象

public class Material
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    [Required]
    [Display(Name="Material")]
    public string MaterialName { get; set; }
}
材料形状抽象类

 public abstract class MaterialShape
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }


    [Required]
    public virtual Material Material { get; set; }
}
从MaterialShape继承的圆形类

  [Table("Rounds")]
public class Round : MaterialShape
{
    [Required]
    [Display(Name="Outside Diameter")]
    public double OuterDiameter { get; set; }
}
下面是我创建的视图模型,用于将所有材质添加到视图中。我使用IEnumerable从数据库中获取所有不同的资料。我还包括了一个用于保存我所选项目的MaterialId

 public class VMRoundMaterial
{
    public Round Round { get; set; }

    [Display(Name="Material")]
    public IEnumerable<SelectListItem> Materials  { get; set; }

    public int MaterialId { get; set; }
}
创建视图

@model SetupSheet.Models.ViewModel.VMRoundMaterial

@{
ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Round</h4>
    <hr />
    @Html.ValidationSummary(true)

    <div class="form-group">
        @Html.LabelFor(model => model.Round.OuterDiameter, new { @class = "control-label col-md-2" })

        <div class="col-md-10">
            @Html.EditorFor(model => model.Round.OuterDiameter)
            @Html.ValidationMessageFor(model => model.Round.OuterDiameter)


        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.Materials, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(m => m.MaterialId, Model.Materials)
        </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>

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
 }
我的[HttpPost]工作不正常。我设置正确了吗?DropDownListFor参数设置是否正确?我是否正确地将selecteditem转换为圆形对象?由于某种原因,ModelState.IsValid返回false。这可能是什么原因造成的? 代码在上失败

roundmaterial.Material.ID = viewmodel.MaterialId;
数据库连接正在工作,但我没有收到结果。我对其他策略持开放态度,以找到一种有效的策略

jstadnicki提出的解决方案

[HttpPost]
    public ActionResult Create(ModelDTO viewmodel)
    {
        try
        {
            if (ModelState.IsValid)
            {

                Round roundmaterial = new Round();

                roundmaterial.OuterDiameter = viewmodel.Round.OuterDiameter;
                roundmaterial.Material.ID = viewmodel.MaterialId;

                db.Rounds.Add(roundmaterial);
                db.SaveChanges();
            }

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

我明白你为什么要用ModelDTO,但我还是有问题


ModelState仍然为false。我认为我们仍然缺少一些东西。

如果我正确理解您的问题:尝试将VMRoundMaterial in post方法更改为ModelDTO,其中ModelDTO的定义如下:

public class ModelDTO 
{
    public Round Round {get;set;}
    public int MaterialId { get; set; }
}

现在检查您是否将获得适当的水合模型。

ModelState
无效,因为您在视图模型(
Round
)中使用了数据模型,并且没有为所需的
材质
属性回传值

通常,用于编辑数据的视图模型不应包括作为数据模型的属性,并且您的视图应为

public class VMRoundMaterial
{
    [Required]
    [Display(Name="Outside Diameter")]
    public double OuterDiameter { get; set; }
    [Display(Name="Material")]
    public int MaterialId { get; set; }
    public IEnumerable<SelectListItem> Materials  { get; set; }
}

旁注:您使用的
roundmaterial.Material.ID=viewmodel.MaterialId可能会抛出一个
NullReferenceException
,因为您尚未初始化属性
Material

ModelDTO在此实例中是圆形的。圆形是从材质形状继承而来的。MaterialShape具有材质类型的材质属性。见上文。您是否建议我使用MaterialID作为数据模型中的键,而不是材质类型/对象。也许是我的物品出了问题,你不会得到收集的材料。视图模型!=DTO模型。请注意,在HTML中,您只找到一个带有MaterialD的,并且您正在获得它,如屏幕截图所示。为了得到材料清单,你需要自己重新生成。代码正确。那么从数据库中重新生成列表,然后将其另存为物料类型?为什么ModelState.IsValid=“false”?ModelState对我来说是个惊喜。但是,请将控制器中的输入模型更改为我在回答中提出并更新的模型。请注意,is仅包含将通过页面上显示的表单发送的数据。检查它是否有效。请记住,在大多数情况下,用于显示数据的模型(aka:ViewModel)和在控制器中发送给您的模型(aka:data Transfers Objects~DTO~)是不同的。
public class ModelDTO 
{
    public Round Round {get;set;}
    public int MaterialId { get; set; }
}
public class VMRoundMaterial
{
    [Required]
    [Display(Name="Outside Diameter")]
    public double OuterDiameter { get; set; }
    [Display(Name="Material")]
    public int MaterialId { get; set; }
    public IEnumerable<SelectListItem> Materials  { get; set; }
}
@Html.LabelFor(m => m.OuterDiameter)
@Html.EditorFor(m => m.OuterDiameter)
@Html.ValidationMessageFor(m => m.OuterDiameter)

@Html.LabelFor(m => m.MaterialId)
@Html.DropDownListFor(m => m.MaterialId, Model.Materials)
@Html.ValidationMessageFor(m => m.MaterialId)