I have a model:
public class VR
{
[Key]
public int ID { get; set; }
public string FullName { get; set; }
public string CreatedBy { get; set; }
public DateTime? Created { get; set; }
public string ModifiedBy { get; set; }
public DateTime? Modified { get; set; }
}
My controller's Edit
function:
// POST: VRs/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VR vR)
{
if (ModelState.IsValid)
{
var Result = (from c in _context.MyVR.Where(c => c.ID == vR.ID) select c).Single();
vR.Created = Result.Created;
vR.CreatedBy = Result.CreatedBy;
vR.ModifiedBy = User.Identity.Name;
vR.Modified = DateTime.Now;
_context.Update(vR);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vR);
}
and I get the error below:
The instance of entity type '
UNTest.ViewModels.VR
' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using anIIdentityGenerator
to generate unique key values.
right click edmx file > update model from data base > Refresh tab > Tables > select the table(you want to update) and press finish that's it.
Attach is used to repopulate a context with an entity that is known to already exist in the database. SaveChanges will therefore not attempt to insert an attached entity into the database because it is assumed to already be there.
You can Attach the entity to avoid loading it from DB (save performance) and update only the fields you want.
This also avoids the problem of your code when you load an instance from the DB (Result
) and track another instance with the same Id (vR
) resulting in an exception.
// POST: VRs/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VR vR)
{
if (ModelState.IsValid)
{
//Attach the instance so that we don't need to load it from the DB
_context.MyVR.Attach(vR);
vR.ModifiedBy = User.Identity.Name;
vR.Modified = DateTime.Now;
//Specify the fields that should be updated.
_context.Entry(vR).Property(x => x.ModifiedBy).IsModified = true;
_context.Entry(vR).Property(x => x.Modified).IsModified = true;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vR);
}
The other way to specify fields that should not be updated.
// POST: VRs/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VR vR)
{
if (ModelState.IsValid)
{
//Attach the instance so that we don't need to load it from the DB
_context.Entry(vR).State = EntityState.Modified;
vR.ModifiedBy = User.Identity.Name;
vR.Modified = DateTime.Now;
//Specify the fields that should not be updated.
_context.Entry(vR).Property(x => x.Created).IsModified = false;
_context.Entry(vR).Property(x => x.CreatedBy).IsModified = false;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vR);
}
In case you use a view model, you can use new
operator to create your data model and copy the fields you want to update:
// POST: VRs/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(VRViewModel vRVM)
{
if (ModelState.IsValid)
{
VR vR = new VR();
//Attach the instance so that we don't need to load it from the DB
_context.MyVR.Attach(vR);
//Set the Id for your model.
vR.Id = vRVM.Id;
//Let's say you also want to update this field from the VM
vR.FullName = vRVM.FullName;
vR.ModifiedBy = User.Identity.Name;
vR.Modified = DateTime.Now;
//Specify the fields that should be updated.
_context.Entry(vR).Property(x => x.ModifiedBy).IsModified = true;
_context.Entry(vR).Property(x => x.Modified).IsModified = true;
_context.Entry(vR).Property(x => x.FullName).IsModified = true;
_context.SaveChanges();
return RedirectToAction("Index");
}
//create your new view model and return it. For demonstration purpose, I return the same view model, in your real code, you can adjust it.
return View(vRVM);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With