首页 > 解决方案 > 使用 ASP.Net MVC 和实体框架在一个视图中编辑对象和相关对象

问题描述

我正在创建一个应用程序,可以在其中创建注释并且可以将一对多的部件添加到注释中。(该应用程序适用于客户要求拖拉机零件的拖拉机打捞场)。我知道以前有人问过类似的问题。但是我找不到任何与我在 EF 和所有方面的情况非常相关的东西。

在一个视图中创建/编辑带有其部分的注释时遇到了很多困难。不过,我想专注于编辑这个问题。

我有两个具有关系的简单 CLR 类。

public class Note
    {
        public int ID { get; set; }
        public string CustomerName { get; set; }
        public string CustomerPhone { get; set; }
        public DateTime DateCreated { get; set; }
        public DateTime DateUpdated { get; set; }
        public string CreatedBy { get; set; }
        public string AssignedTo { get; set; }
        public virtual ICollection<Part> Parts { get; set; }
    }
public class Part
    {
         
         public int PartID { get; set; }
         public string PartNumber { get; set; }
         public string Description { get; set; }
         public int NoteID { get; set; }
         public virtual Note Note { get; set; }
    }

和 DbContext:

public class CallNoteContext : DbContext
    {
        public CallNoteContext() { }
        public DbSet<Note> Notes { get; set; }
        public DbSet<Part> Parts { get; set; }
    }

我的问题是将两个实体的数据绑定到编辑视图,访问视图中的数据以进行编辑并将注释和多个部分保存到 httppost 操作中的数据库。

我已经尝试了很多东西,但是在阅读了很多文章之后,我不断地回到这个控制器和视图。对我来说,这似乎应该有效。但显然我错过了一些东西。

这是来自我的控制器的编辑和发布操作。

private CallNoteContext db = new CallNoteContext();

        // GET: Note/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Note note = db.Notes.Find(id);
            var model = new Note()
            {
                CustomerName = note.CustomerName,
                CustomerPhone = note.CustomerPhone,
                DateCreated = note.DateCreated,
                DateUpdated = note.DateUpdated,
                CreatedBy = note.CreatedBy,
                AssignedTo = note.AssignedTo,
                Parts = note.Parts 
            };
            if (note == null)
            {
                return HttpNotFound();
            }
            return View(model);
        }

        // POST: Note/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,CustomerName,CustomerPhone,DateCreated,DateUpdated,CreatedBy,AssignedTo,Parts")] Note note)
        {
            if (ModelState.IsValid)
            {
                foreach(var p in note.Parts)
                {
                    db.Entry(p).State = EntityState.Modified;
                    db.SaveChanges();
                }
                db.Entry(note).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(note);
        }

当我尝试在下面的视图中为 p.PartNumber 和 p.Description 制作编辑器时,它会中断,但找不到这些属性。我有一种感觉,我在控制器的“获取”操作中做错了什么。但我很难弄清楚出了什么问题。

顺便说一句,IntelliSense 表示控制器未发现任何问题。

这是我的编辑视图。

@model CallNote.Models.Note

<head>
    <script src="~/Scripts/jquery-3.4.1.js" type="text/javascript"></script>
</head>

<h2>Edit</h2>

@using (Html.BeginForm())
{
@Html.HiddenFor(model => model.ID)

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

    <div class="form-group">
        @Html.LabelFor(model => model.CustomerPhone, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.CustomerPhone, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.CustomerPhone, "", new { @class = "text-danger" })
        </div>
    </div>
@*There are editors here for all of the properties, but I didn't list them to save space.*@



@*The app always breaks when it gets to this foreach because it says it can't find p.PartNumber. What is wrong?

 @foreach (var p in Model.Parts)
    {
        <div>
@*I also tried just using p.PartNumber, but it says p doesn't exist in current context.
            @Html.EditorFor(p => p.PartNumber)
            @Html.EditorFor(p => p.Description)
        </div>
    }

    <div id="partInfo" style="display:none">
        @Html.EditorFor(p => p.PartNumber)
        @Html.EditorFor(p => p.Description)
    </div>

    <div id="btnWrapper">
        <input id="btnAddPart" type="button" value="Add Part" />
    </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>
</div>
}
@*The script below works, allowing you to add part editors*@
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
<script>
    $(document).ready(function () {
        $("#btnAddPart").click(function () {
            var partinfo = $("#partInfo").html();
            $("#partInfo").append(partinfo);
        });
    });
</script>

我也不确定 httppost 操作是否有效。我还不能尝试它,因为我什至无法加载编辑视图。因此,如果您对此也有任何建议,请告诉我。

我刚刚开始使用MVC,所以详细的答案会很棒!

标签: c#asp.net-mvcentity-framework

解决方案


您必须在注释中包含部分

....
  Note note = db.Notes
                .Include(i=> i.Parts)
                .FirstOrDefault(i=>i.ID==id);
 if (note == null)
   {
     return HttpNotFound();
    }
.....

并且由于您使用的是编辑器,因此将 foreach 循环替换为 for 循环

@if( Model.Parts!=null && Model.Parts.Count >0)
{
@for (var i=0; i< Model.Parts.Count; i++)
{

 <div id="partInfo" style="display:none">
        @Html.EditorFor(model => model.Parts[i].PartNumber)
        @Html.EditorFor(model => model.Parts[i].Description)
    </div>
   ...... and so on for all properties
}
}

并从动作中删除绑定

[HttpPost]
[ValidateAntiForgeryToken]
 public ActionResult Edit(Note note)
 {
  if (!ModelState.IsValid)  return View(note);
            
var existedNote = db.Notes
  .Include(i=> i.Parts)
    .FirstOrDefault(i=>i.ID==note.ID);

  if(existedNote!=null) 
 {
  db.Entry(existedNote).CurrentValues.SetValues(note);
 

if(note.Parts!=null && note.Parts.Count > 0)
{
   foreach( var part in note.Parts)
   {
     var existingPart = existingNote.Parts.FirstOrDefault(p => p.PartID == part.PartID);

            if (existingPart == null)
            {
                existingNote.Parts.Add(part);
            }
            else
            {
                context.Entry(existingPart).CurrentValues.SetValues(part);
            }
     }
  }
     
    db.SaveChanges();
 }
    return RedirectToAction("Index");
 }
 return View(note);
}
````

推荐阅读