Databases Reference
In-Depth Information
It is a dynamic, parameterized update statement that sets the UnitsInStock column to its
new value, 50 (specified as the
@0
parameter), but only if its current value (specified as the
@2
parameter) is still the same as the original value
20
saved when the Product entity was
retrieved from the database. If the current value of the UnitsInStock column does not
match the original value, no records are updated, and the
SaveChanges
method of the
ObjectContext
class throws the
OptimisticConcurrencyException
.
NOTE
If you are using Microsoft SQL Server, you can take advantage of the
ROWVERSION
(formerly known as
TIMESTAMP
) column type, designed specifically for optimistic concur-
rency control. When any changes are made to a row, the server automatically updates
its
ROWVERSION
column value. If your entity has a property mapped to a
ROWVERSION
column, it is the only one whose Concurrency Mode needs to be set to
Fixed
.
Otherwise, you will want to set it for
all
entity properties and avoid partial data loss.
What does your application need to do when it encounters an
OptimisticConcurrencyException
? Usually you simply want to let the current user know
that somebody else has already changed the record he is trying to modify, let him take
note of the changes he was trying to make, and refresh the record to see the other users'
modifications. The following code illustrates this scenario from the pure data access point
of view:
Product product = context.Products.First(p => p.ProductName == “Chai”);
product.UnitsInStock = 50;
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException e)
{
context.Refresh(RefreshMode.StoreWins,
e.StateEntries.Select(s => s.Entity));
}
Notice how after catching an
OptimisticConcurrencyException
, the code calls the
Refresh
method of the
ObjectContext
. This method takes a
RefreshMode
enumeration,
which determines whose changes will be preserved and an
IEnumerable
of entity objects
that need to be refreshed. The
RefreshMode
.
StoreWins
value means that changes made by
the other users will be preserved. You can also pass the
ClientWins
value, which would
ignore changes of other users and keep the modifications made by the current user. The
exception object itself provides a list of entities that failed to save—it is retrieved with the
help of the
StateEntries
property, which returns a collection of the familiar
ObjectStateEntry
objects, providing access to their entities.