I am creating an application where a Note can be created and one to many Parts can be added to the note. (The application is for a tractor salvage yard where customers call for tractor parts). I know similar questions have been asked before. But I couldn't find anything very relevant to my situation with EF and all.
I am having a lot of difficulty with creating/editing a Note with its Parts in one view. I want to focus on editing for this question, though.
I have two simple CLR classes with a relation.
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; }
}
And the DbContext:
public class CallNoteContext : DbContext
{
public CallNoteContext() { }
public DbSet<Note> Notes { get; set; }
public DbSet<Part> Parts { get; set; }
}
My problem is binding the data from both entities to the edit view, accessing the data in the view for editing and saving the note and and multiple parts to the database in the httppost action.
I have tried a lot of things, but after reading a lot of articles, I keep coming back to this for the controller and view. To me it seems like this should work. But obviously I am missing something.
Here is the edit and post actions from my controller.
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);
}
When I try to make editors for p.PartNumber and p.Description in my view below, it breaks with the exception that it can't find these properties. I have a feeling that I am doing something wrong in the "get" action of the controller. But I am having a hard time figuring out what is wrong.
By the way, IntelliSense is saying No Issues Found for the controller.
Here is my Edit view.
@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>
Also I am unsure if the httppost action will work. I have not been able to try it yet as I cannot get the Edit view to even load yet. So if you have any suggestions for that too, let me know.
I am just getting started with MVC, so a detailed answer would be super!