Reputation: 21
I am working on an ASP.NET MVC project with EF in C# from a book and this part is to avoid updating an entity concurrently from different sessions. The book is great but unfortunately in this part the explanation is not sufficient and I would appreciate if someone could help me understand. I will try to omit irrelevant code. The model basically has only one property "Name" so it is really simple:
[HttpPost]
public ActionResult Edit(int? id, byte[] rowVersion)
{
string[] fieldsToBind = new string[] { "Name", "RowVersion" };
var categoryToUpdate = db.Categories.Find(id);
if (TryUpdateModel(categoryToUpdate, fieldsToBind))
{
try
{
db.Entry(categoryToUpdate).OriginalValues["RowVersion"] =
rowVersion;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException ex)
{//... and the code goes on to handle the concurrent update
// scenario
}
Here is what I don't understand: If the TryUpdateModel method successfully updated the model, and bound the new values "Name" and "RowVersion" (that were provided by the view) why do I have to include this line: db.Entry(categoryToUpdate).OriginalValues["RowVersion"] = rowVersion;? What does this line do exactly? Why is it required for the exception to be thrown? Thanks
Upvotes: 2
Views: 347
Reputation: 11
This is related to how EF works internally. When generating the UPDATE command for this statement EF will look for a row that has the RowVersion value existing in OriginalValues.
That line needs to be added because the entity is loaded from DB with this line:
db.Categories.Find(id);
Because latest values of the entity is loaded from DB with this line there will be no concurrency exception unless you change the RowVersion value stored in OriginalValues.
If entity was not loaded from DB and update was performed by attaching it to the context then there would be no need for setting RowVersion in OriginalValues.
Upvotes: 1