Reputation: 12925
I'm new to managing concurrency so apologies if this question is ill-informed.
In past projects I've implemented concurrency checking by wrapping operations in a TransactionScope - something like this:
using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
var copiedFolder = new Folder();
using (var db = CreateContext())
{
// do stuff safely
}
scope.Complete();
return copiedFolder;
}
However I've just come across Entity Framework's approach to concurrency: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
And I'm wondering when it's better to use one over the other. Technically, are they the same thing? If not, how do they differ?
Upvotes: 2
Views: 3198
Reputation: 739
The Timestamp
attribute can only be applied to a single byte array property, whereas the ConcurrencyCheck
attribute can be applied to any number of properties with any data type.
Upvotes: 2
Reputation: 109185
Technically, are they the same thing?
No, they're not. They're not even related, necessarily.
TransactionScope
is used to ensure that database changes are being committed in one transaction. You typically use TS together with Entity Framework when for whatever reason you need multiple SaveChanges
calls to happen within one database transaction. A typical scenario is saving an entity and setting its generated primary key in some property of another entity. (Note that one SaveChanges
call is always in one transaction and usually no TS is necessary).
TS does not resolve any concurrency conflicts. When two users affect the same records, the last user who commits the transaction wins.
Concurrency resolution is about what to do when two different users try to change the same records "simultaneously". The link you quote elaborates on the most common strategy, optimistic concurrency, which is supported by EF. The most common approach in EF is to introduce a TimeStamp
column in database tables which (at least in SQL server) is incremented automatically at each update of the record. The timestamp columns are also introduced in the conceptual model (= class model) and marked as [Timestamp]
(data annotation) or IsConcurrencyToken
(fluent mapping), so the property will be included in update and delete commands. Briefly it looks like this:
UPDATE x SET y WHERE x.TimeStamp = <value when the record was fetched>
When another user updated the record in the mean time, EF notes zero records affected and throws a DbUpdateConcurrencyException
. You can deal with this exception in a number of ways.
Upvotes: 2
Reputation: 11177
They are not the same thing. Concurrency as a mechanism is there to ensure that no overwrite is made when two users are accessing same entity concurrently.
I'll give you an example. Imagine a row with Id 541 that has Name set to "Alex".
Assume you have two users, User A and User B, both attempting to modify name of that row. The following scenario is what concurrency is all about:
Changes done by user A are overwritten without user B knowing about it.
What concurrency is doing is basically ensuring that if there has been a change in value between User B read and User B change commit, it will throw DbConcurrencyException indicating that entity has been changed thus providing user B ability to cancel the saving or proceed anyway.
When you want to ensure that particular property is safe from invisible overwriting, you mark it with [ConcurrencyCheck]. Entity Framework by the default does updates by providing Id (identity) column in WHERE clause. When another column is marked with [ConcurrencyCheck], it will also add additional condition to UPDATE command which will basically in this example be WHERE NAME = 'Alex'. So since Alex is no longer value in the database (User A has changed it), it will do 0 updates which will internally result in an exception.
Upvotes: 4