ViewModel DropDownList和HTTP Post Controller

时间:2016-03-27 21:34:49

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

我的创建操作的Post Controller存在一些问题。下面是我的模型,Round,Material,MaterialShape,RawMaterial。我的主要目标是将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中的Round Inherited Class

  [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; }
}

控制器创建操作

  public ActionResult Create()
      {
        var model = new VMRoundMaterial();
        using (var db = new DbContext())
        {
            model.Materials = db.Materials.ToList().Select(x => new SelectListItem
            {
                Value = x.ID.ToString(),
                Text = x.MaterialName
            });
        } 
        return View(model);
    }

创建视图

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

Round Create View with Combobox from Database

如您所见,我完成了将列表添加到数据库中。我在创建[发布]操作中将Viewmodel转换回我的Datamodel时遇到问题。

 [HttpPost]
    public ActionResult Create(VMRoundMaterial 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();
        }
    }

Viewmodel null 我的[HttpPost]无法正常工作。我是否正确设置了?如何正确设置DropDownListFor参数?我是否将我的选择项正确转换为Round对象?由于某种原因,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 Values

ModelState.IsValid = "false"

我理解你为什么要使用ModelDTO,但我仍然遇到问题。

ModelState仍然是假的。我想我们在这里仍然缺少一些东西。

2 个答案:

答案 0 :(得分:1)

ModelState无效,因为您在视图模型中使用了数据模型(Round)而没有回发所需Material属性的值。

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

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

另请注意,您的展示属性需要位于int MaterialId,而不是IEnumerable<SelectListItem> Materials,以便创建与MaterialId相关联的标签(目前,点击'标签'不会设置焦点到<select>元素。那么视图将是

@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)

旁注:您在POST方法中使用roundmaterial.Material.ID = viewmodel.MaterialId;可能会抛出NullReferenceException,因为您尚未初始化属性Material

答案 1 :(得分:0)

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

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

现在检查一下你是否会得到适当的水合模型。