Hi
I have a master-detail view with 2 tables :
DefaultVisitProductHeaders -> Master table
DefaultVisitProductDetails -> Detail table
In my view, i've using ajax request to give end-user to add/update/remove details, then save them in tempData (not in _dbContext). Here is my master-detail view (for edit mode):
@model DefaultVisitProductHeaders<h4>Edit Drugs Package</h4><hr /><div class="row"><div class="col-md-6"> <form id="frmEditPackageHeaderItem" asp-action="Update" method="post"><div asp-validation-summary="All" class="text-danger"></div><input type="hidden" id="hdnDefaultVisitProductHeaderRowID" asp-for="DefaultVisitProductHeaderRowID" value="@Model.DefaultVisitProductHeaderRowID" /><div class="form-group"><label asp-for="DefaultVisitProductHeaderName" class="control-label"></label><input asp-for="DefaultVisitProductHeaderName" class="form-control" value="@Model.DefaultVisitProductHeaderName" /><span asp-validation-for="DefaultVisitProductHeaderName" class="text-danger"></span></div><br /><h4>Package Details List</h4><hr /><div id="divPackageDetails" class="container"> @Html.RenderAction("GetPackageDetails", "Package", new { id = Model.DefaultVisitProductHeaderRowID })</div><div class="text-right"><button type="submit" id="btnUpdate" class="btn btn-success">Save</button> @Html.ActionLink("Back", "Index", "Package")</div></form></div></div><div id="divPopup"></div> @section Scripts{ <script src="~/js/jquery.validate.min.js"></script><script src="~/js/jquery.validate.unobtrusive.min.js"></script> }
My problem is that when, click on save button to update database, i'm facing this error (for added entities) :
InvalidOperationException: The instance of entity type 'DefaultVisitProductHeaders' cannot be tracked because another instance with the same key value for {'DefaultVisitProductHeaderRowID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values. Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap<TKey>.ThrowIdentityConflict(InternalEntityEntry entry)
Here is my update action :
[HttpPost] [ValidateAntiForgeryToken] public IActionResult Update([Bind("DefaultVisitProductHeaderRowID, DefaultVisitProductHeaderName")] DefaultVisitProductHeaders packageHeader) { if (this.ModelState.IsValid) { var curPackageHeader = _dbContext.DefaultVisitProductHeaders.Find(packageHeader.DefaultVisitProductHeaderRowID); curPackageHeader.DefaultVisitProductHeaderName = packageHeader.DefaultVisitProductHeaderName; this.AttachPackageDetailsToDbContext(curPackageHeader); _dbContext.SaveChanges(); return RedirectToAction("Index", "Package"); } return View("Edit", packageHeader); }
And here is my helper methods (AttachPackageDetailsToDbContext, GetPackageDetailsList) :
private void AttachPackageDetailsToDbContext(DefaultVisitProductHeaders packageHeader) { List<DefaultVisitProductDetails> lstPackageDetails = this.GetPackageDetailsList(); List<DefaultVisitProductDetails> lstItemsAdded = lstPackageDetails.Where(d => d.IranHealthEntityState == IranHealthEntityState.Added).ToList(); List<DefaultVisitProductDetails> lstItemsModified = lstPackageDetails.Where(d => d.IranHealthEntityState == IranHealthEntityState.Modified).ToList(); List<DefaultVisitProductDetails> lstItemsDeleted = lstPackageDetails.Where(d => d.IranHealthEntityState == IranHealthEntityState.Deleted).ToList(); foreach (DefaultVisitProductDetails detailItem in lstItemsAdded) { _dbContext.DefaultVisitProductDetails.Add(detailItem); // Cause error!! } foreach (DefaultVisitProductDetails detailItem in lstItemsModified) _dbContext.Entry(detailItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified; foreach (DefaultVisitProductDetails detailItem in lstItemsDeleted) _dbContext.Entry(detailItem).State = Microsoft.EntityFrameworkCore.EntityState.Deleted; } private List<DefaultVisitProductDetails> GetPackageDetailsList() { List<DefaultVisitProductDetails> lstResult = null; #region Getting lstPackageDetails from tempData, if does not exists, generate new list! var tmp = TempData.Peek("_lstPackageDetails"); if (tmp != null) { lstResult = JsonConvert.DeserializeObject<List<DefaultVisitProductDetails>>(tmp.ToString(), new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects }); } if (lstResult == null) { lstResult = new List<DefaultVisitProductDetails>(); } #endregion return lstResult; }
Where is my problem & how to solve it?
Thanks in advance.