【问题标题】:How to edit Entity which spans over 4 tables如何编辑跨越 4 个表的实体
【发布时间】:2013-10-20 08:09:49
【问题描述】:

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

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

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

所有广告最多可在一台设备上投放。一个设备有一个类别、一个制造商、一个状态和 0..n cmets。这是被剥离的。在学习 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() 调用之后它不会被写入数据库。

【问题讨论】:

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


    【解决方案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);
    }
    

    【讨论】:

    • 这解决了正确创建Dropdownlist的问题,但不是POST方法的问题。我可以保存editviewmodel.dev 部分,但这仅包含name 而不是category.
    • 刚刚添加了一些修改,不知道有没有帮助。您的视图不会修改您设备的类别。您必须根据下拉列表的选定值自己制作。
    • 我已经在我的开篇文章中实现了你的更改,但仍然有一些奇怪的行为。我已将设备更改为 cat "Router",并逐步执行 POST 方法。它将 Category 更改为 ID 1,即 router 并保存。但返回索引后,它仍然在智能手机的旧 ID 上。
    • 但设备保存正确?如果是,则可能是您的浏览器存在缓存问题。
    • 不,它没有被保存。尽管调用了db.SaveChanges(),但保存并没有发生。我已经通过不同的浏览器并查看表格进行了重新检查。未进行任何更改。
    【解决方案2】:

    在我让这个问题休息几天后,我找到了一个可行的解决方案。实际编辑项目及其属性并将其保存到数据库的最后一个问题,一旦我设法缩小可能发生错误的位置,就非常简单了。

    [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()。

    现在就像一个魅力。但是,我会将解决方案单击到我的下拉列表助手答案。否则就不公平了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 2015-07-27
      • 2011-07-04
      • 2011-08-27
      • 2019-08-11
      • 2010-09-24
      • 2012-02-27
      • 1970-01-01
      相关资源
      最近更新 更多