如何编辑跨越4个表的实体

时间:2013-10-20 08:09:49

标签: c# entity-framework asp.net-mvc-4 ef-code-first

重要提示:我已编辑此问题以反映Jannagy02的回答,该回答消除了下拉列表问题

我有一个关于ASP.NET MVC 4和实体框架的概念性问题。

首先,让我们来看看我的模型:EDM

此广告最多可归待一台设备。一个设备有一个类别,制造商,状态和0..n评论。这被剥夺了。学习MVC时,我不想过于复杂。因此,我们只需关注DeviceCategory,同时忽略存储库和工作单元模式等内容。

在我设置了它之后,脚手架发挥了它的魔力,生成的视图只显示了设备的Name属性。

我的计划是,在创建或更新设备时,用户(而不是管理员)只能从已经存在的类别中进行选择。因此,下拉列表。

为此,我创建了一个ViewModel:

public class DeviceEditViewModel
{
    public Device dev { get; set; }

    public int? SelectedManufactor { set; get; }
    public IEnumerable<SelectListItem> Manufactors { get; set; }

    public int? SelectedCategory { set; get; }
    public IEnumerable<SelectListItem> CategoriesListItems { get; set; }
}

GET编辑方法如下所示:

public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var device = db.Devices.Find(id);
    var vm = new DeviceEditViewModel
                 {
                      dev = device,
                      Categories = db.Categories.ToList().Select(x => new SelectListItem 
                      {
                          Value = x.ID.ToString(), 
                          Text = x.Name, 
                          Selected = x == device.Category
                      })
                  };
    return View(vm);
}

这是我的第一个问题:生成的下拉列表无法获取设备的实际类别。那么我该如何选择实际类别作为选定值?

其次,当我点击保存按钮时,如何将此选定的ListItem作为设备模型的类别注入,这在post方法中如何反映,如下所示:

//Edited to reflect answer
public ActionResult Edit(DeviceEditViewModel editViewModel)
{
    if (ModelState.IsValid)
    {
        Device device = editViewModel.dev;
        if (editViewModel.SelectedCategory != null)
        {
            Category selectedCat = db.Categories.Single(x => x.ID == editViewModel.SelectedCategory.Value);
            device.Category = selectedCat;
        }

        db.Entry(device).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(editViewModel);
}

这是我视图的DropDownList部分:

<div class="control-group">
    @Html.LabelFor(model => model.dev.Category, new { @class = "control-label" })

    <div class="controls">
        @Html.DropDownListFor(x => x.CategoriesListItems, Model.CategoriesListItems)
        @Html.ValidationMessageFor(model => model.dev.Category, null, new { @class = "help-inline" })
    </div>
</div>

剩下的问题在于POST方法。我已经写了一段时间,以便能够更好地调试它。实际问题是:

使用类别更新设备,但在db.SaveChanges()调用后,它不会写入数据库。

2 个答案:

答案 0 :(得分:1)

首先修改ViewModel,使其包含所选值:

public class DeviceEditViewModel
{
    public Device dev { get; set; }
    public IEnumerable<SelectListItem> Manufactors { get; set; }

    public int? SelectedCategory { set; get; }
    public IEnumerable<SelectListItem> Categories { get; set; }
    public IEnumerable<SelectListItem> Status { get; set; }
}

第二

在视图中绑定SelectedCategory以便它可以发布:

@Html.DropDownListFor(m => m.SelectedCategory, m.Categories)

或使用此

@Html.DropDownListFor(m => m.SelectedCategory, new SelectList(m.Categories, "ValuePropertyName", "TextPropertyName"))

将ViewModel发布到编辑而不是设备:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(DeviceEditViewModel devm)
{
    if (ModelState.IsValid)
    {
        devm.device.CategoryId = devm.SelectedCategory; // <- Main thing to do
        db.Entry(devm.device).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(devm);
}

答案 1 :(得分:0)

在我让问题休息了几天之后,我找到了一个有效的解决方案。实际编辑项目及其属性并将其保存到数据库的最后一个问题,一旦我管理以缩小可能发生错误的位置,这是非常微不足道的。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(DeviceEditViewModel editViewModel)
{
    if (ModelState.IsValid)
    {
        //non-working: Device device = editViewmodel.env;
        Device device = db.Devices.Single(x => x.Id == editViewModel.dev.Id); /*working*/
        if (editViewModel.SelectedCategory != null)
        {
           device.Category = db.Categories.Where(x => x.ID == editViewModel.SelectedCategory).Select(x => x).Single();
        }
        db.Entry(device).State = EntityState.Modified;
        db.Devices.AddOrUpdate(device);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
        return View(editViewModel);
}

我没有使用所使用的Viewmodel,而是通过比较ID并在此实体上调用AddOrUpdate()来从数据库中获取要编辑的设备。

现在就像魅力一样。然而,我会给解决方案点击我的下拉列表助手答案。否则不公平。