locked
Problem with batch updating for master-details entities. RRS feed

  • Question

  • 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


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx

    Thursday, May 28, 2020 10:11 AM

All replies