Reputation: 472
I've encountered an issue when trying to update my context in my Edit action:
[HttpPost]
public IActionResult Edit(Model.LeaveApplication leaveApplication) {
ViewBag.Title = "Edit Leave Application";
ViewBag.leavePeriodList = context.LeavePeriod.ToList();
ViewBag.LeaveTypeList = context.LeaveType.ToList();
try {
if (ModelState.IsValid) {
if (!validateDateRanges(leaveApplication, "edit")) {
return View(leaveApplication);
}
leaveApplication.NumDays = (float)CalculateNoOfDays(leaveApplication);
context.LeaveApplication.Update(leaveApplication);
context.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DbUpdateException) {
ModelState.AddModelError("", "Unable to edit leave application. " +
"Please try again, and if the problem persists, " +
"please see your system administrator.");
}
return View(leaveApplication);
}
What I am trying to do is to check if there is more than 1 records in order to validate date ranges. If there is only 1 record, I will then skip the validation and proceed to update the context. However, I get an error saying:
The instance of entity type 'LeaveApplication' cannot be tracked because another instance of this type with the same key is already being tracked.
What is causing this problem?
Here is my constructor code:
public class LeaveApplicationController : Controller {
LeaveDBContext context;
private readonly UserManager<ApplicationUser> userManager;
private readonly SignInManager<ApplicationUser> signInManager;
public LeaveApplicationController(LeaveDBContext context, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) {
this.context = context;
this.userManager = userManager;
this.signInManager = signInManager;
}
}
Upvotes: 0
Views: 1356
Reputation: 239230
You should never attempt to save an object created via a post. There's a number of security reasons why this is the case, but you've also stumbled onto a practical one based on the way EF works.
It's hard to tell exactly without more of your codebase, but at some point this particular LeaveApplication
instance is loaded into your context, which then begins tracking it. When you attempt to save a different LeaveApplication
instance (i.e. the one that was posted), EF cannot because it's not tracking that instance, but rather the one that was loaded earlier.
What you should do instead is post to a view model class. Then, pull the LeaveApplication
instance you want to edit directly from your context, and map over the data from your view model onto it. Finally, save that instance. Then, you will no longer have any issues, and you get the side benefits of preventing over-post hacks and other post-data tampering. Also, your LeaveApplication
id should be part of the URL. Never trust a posted id. Period. Since an id in the URL uniquely identifies the resource, you can easily implement object-level permissions based on that.
Upvotes: 3