【问题标题】:MVC5 / Entity | Update/Create Complex ModelMVC5 / 实体 |更新/创建复杂模型
【发布时间】:2018-04-01 11:51:00
【问题描述】:

我已经创建了一个复杂的模型,并且一直在努力寻找一种将表单数据添加/更新到数据库的方法。

基本上我的模型如下所示:

namespace Models
{
    public class ModelClass1
    {
        public int Id { get; set; }
        public string Prop1 { get; set; }
        public string Prop2 { get; set; }

        public ICollection<ModelClass2> ModelClass2 { get; set; }
    }
    public class ModelClass2
    {
        public int Id { get; set; }
        public string Prop3 { get; set; }
        public string Prop4 { get; set; }

        public ICollection<ModelClass3> ModelClass3 { get; set; }
    }

    public class ModelClass3
    {
        public int Id { get; set; }
        public string Prop5 { get; set; }
        public string Prop6 { get; set; }
    }
}

我为 ModelClass1 创建了一个脚手架 CRUD 控制器,并尝试使用一个 Edit 类更新所有 3 个实体。

我的编辑(获取/发布)类:

// GET
public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    ModelClass1 ModelClass1 = db.ModelClass1
        .Include(i => i.ModelClass2.Select(c => c.ModelClass3))
        .Where(x => x.Id == id)
        .Single();

    if (config == null)
    {
        return HttpNotFound();
    }
    return View(ModelClass1);
}


// POST
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ModelClass1 ModelClass1)
{
    if (ModelState.IsValid)
    {
        db.Entry(ModelClass1).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(ModelClass1);
}

我选择使用编辑器模板来填充编辑视图中的表单,因此 Edi.cshtml 将如下所示:

@model ModelClass1

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Prop1, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Prop1, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Prop1, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Prop2, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Prop2, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Prop2, "", new { @class = "text-danger" })
            </div>
        </div>

        @Html.EditorFor(model => model.ModelClass2, new { htmlAttributes = new { @class = "form-control" } })

        @Html.EditorFor(model => model.ModelClass2.FirstOrDefault().ModelClass3, new { htmlAttributes = new { @class = "form-control" } })

    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
}

并为我的 3 个模型类中的每一个创建了类似于下面的模板:

@model ModelClass2
<div class="form-group">
    @Html.LabelFor(model => model.Prop3, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Prop3, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Prop3, "", new { @class = "text-danger" })
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.Prop4, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Prop4, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Prop4, "", new { @class = "text-danger" })
    </div>
</div>

数据显示正确,然后我调用 Edit 控制器,但是当我修改表单中的数据并发布它调用 HTTPPost Edit 方法时,我收到以下错误:

附加类型为“ModelClass3”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

如果我从控制器/视图中完全删除 ModelClass3,我不会收到任何错误,但修改后的数据不会保存到数据库中。

我很确定我的方法不是最好的,所以任何帮助都将不胜感激,因为我的想法已经不多了。

【问题讨论】:

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


    【解决方案1】:

    首先,我不建议直接在前端使用您的域实体。我将为您的域实体创建一个视图模型 (VM)。无论如何,

    您报告的此错误可能是由于实体未附加到上下文。所以你应该在将状态设置为 Modified 之前附加它:

    // POST
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ModelClass1 ModelClass1)
    {
        if (ModelState.IsValid)
        {
            db.Attach(ModelClass1);
            db.Entry(ModelClass1).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(ModelClass1);
    }
    

    但是我更喜欢先从数据库中获取实体,然后更新属性:

    // POST
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ModelClass1 ModelClass1)
    {
        if (ModelState.IsValid)
        {
            ModelClass1 entityFromDB = db.ModelClass1
               .Include(i => i.ModelClass2.Select(c => c.ModelClass3))
               .Where(x => x.Id == id)
               .Single();
            MapProperties(entityFromDB, ModelClass1); // You could use a mapper (Auto Mapper)
            db.Entry(ModelClass1).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(ModelClass1);
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多