Difference between Entity Framework's ConcurrencyCheck and standard TransactionScopes? - c#

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?

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:
User A reads entity from the database.
User B reads entity from the database.
User A modifies value of Name to "Alexander" and commits change to
database.
User B modifies value of Name to "Alexander B" and commits change to
database.
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.

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.

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.

Related

How do I compare an entity in my local context with the one in the database in EF Core?

EF Core 6 and .NET 6.
Suppose all my entities have a LastUpdateAt property, which is a DateTime that gets updated every time an entity is added or modified.
I get an entity from the context and show it to the user (web page, WPF window, whatever). At some point, the user clicks a Save button.
Before I save, I want to check if the entity has been updated by someone else since I got my copy. However, I'm struggling to see how to do this.
If I query the context, it just gives me back the entity I already have (including any changes my user has made).
If I refresh the entity, it overwrites the one in my context, losing my user's changes.
How do I check if the database version has a newer time stamp than the one in my context?
Thanks
Moving the discussion here since I need to paste longer text. In this article it's said, during SaveChanges(), if the DATABASE version was modified in the mean time it will throw DbUpdateConcurrencyException. In that exception you have all 3 values and YOU can decide on how to resolve the conflict:
Resolving a concurrency conflict involves merging the pending changes from the current DbContext with the values in the database. What values get merged will vary based on the application and may be directed by user input.
There are three sets of values available to help resolve a concurrency conflict:
Current values are the values that the application was attempting to write to the database.
Original values are the values that were originally retrieved from the database, before any edits were made.
Database values are the values currently stored in the database.
If you are loading an entity, keeping a DbContext instance open, updating that entity, then saving to the same DbContext instance then by default you are relying on EF to manage concurrency. This follows a "last in wins". You can let EF manage the concurrency by adding a [ConcurrencyCheck] on the LastUpdateAt property or using a Row Version via [Timestamp]. This will cause EF to fail updating if the underlying data has been updated. From there you have to decide how you want to handle it.
If you want to perform the concurrency check yourself then there are a couple of options.
Structure your code to shorten the lifespan of the DbContext using either detached entities or projected View Models. This will generally have flow-on benefits to your code performance as the original longer-lived DbContext can easily find ways to cause bloat, or accumulate "poisoned" entities if alive too long. Automapper is a great tool to assist here where you can use ProjectTo to get the view models, then Map(source, destination) to copy the values across afterward. In this way you load the data including the last modified at value, make your changes, then when saving, you load the data, validate the modified at etc. then copy the values across and save.
Scope a DbContext instance to check the data before saving.
.
private DateTime getFooLastUpdateAt(int fooId)
{
using(var context = new AppDbContext())
{
var lastUpdateAt = context.Foos
.Where(x => x.FooId == fooId)
.Select(x => x.LastUpdateAt)
.Single();
return lastUpdateAt;
}
}
This could use an injected DbContext factory or such to create the DbContext instance..

How do I determine if a record is new or not before adding it to the DbSet

I have a prepare function for saving records to the database that is probably a little overkill, but the idea was that I could add on to it at a later date.
public void Prepare<T>(T model) where T : class {
var key = ReflectionHelper.GetAttribute<T, KeyAttribute>();
if(null == key) { return; }
SetContext<T>();
var set = DbManager.Context.Set<T>();
object id = key.GetValue(model);
object def = key.PropertyType.GetDefaultValue();
if(id == def) { set.Add(model); }
}
The current implementation is just checking that the primary key of the record is a default value (typically 0) and then adds it to the dataset. This works for 90% of cases where tables would be built with an auto-incrementing key, however, I'm running into an issue for a table where the key is generated manually for each record, which means that it is set before inserting it into the DB.
This is obviously not ideal with the above function, which is failing the check and not actually saving it to the DB. I know that Entity Framework must have some sort of internal test to check whether a record is new or not to determine whether it needs to do an UPDATE or an INSERT and AFAIK it doesn't rely on the ID being set beforehand or I'd be running into the same issue with EF's code that I am with the above function. Is there a way that I can pull the result from that check instead of the way I'm currently doing it?
This is where Generic "one size fits all" approaches start to fall down. They work efficiently so long as the implementations are identical. As soon as you have an exceptional case it means introducing complexity.
In situations where the key cannot reflect whether an entity is new or existing (I.e. 0 / null = new) then the typical approach would be to attempt to load the entity to perform the Update, otherwise insert.
var existingEntity = set.SingleOrDefault(x => x.Id == id);
if (existingEntity != null)
{
Mapper.Map(model, existingEntity);
}
else
{
existingEntity = set.Add(model);
}
The issue that can come up with "Upsert" implementations is that the application can start accidentally inserting records that you expect to exist, and should have probably handled if they don't. (Stale data, tampering, etc.) My recommendation with systems is to be explicit with dedicated Add/Insert vs. Update method call chains.
DbSet.Update can also work to manage update or insert scenarios but this is a less optimal compared to using EF's change tracker as it will generate an UPDATE SQL statement for all columns whether they changed or not. If you manually update all of the columns or use Automapper's Map method to copy across the values, the change tracker will only generate a statement for the columns that changed. This also gives you control over ensuring that in update scenarios that only allowed values can be changed. For instance the UI is only expected to change some fields, worst case if you are passing full entities back from the client that other values in the model cannot be tampered with when your manual copy over or Automapper mappings only transfer expected field values.

C# EF 6 CurrentValues.SetValues cannot change Object's Key Information

I have seen other questions about this same error, but I am unable to correct the error with those suggestions in my code; I think that this is a different problem and not a duplicate.
I have an app that makes a series of rules, of which the user can set properties in the GUI. There is a table of Rules in a connected database, with the primary key on the Rule.Id. When the user saves changes to a rule, the existing rule gets "IsActive=0" to hide it, then a new database record is made with the properties from the GUI written to the database. It looks to the user as though they have edited the rule, but the database actually sees a new rule reflecting the new properties (this allows for a history to be kept), connected to the old rule by another reference field.
In the C# code for the app, the View Model for each rule contains an EF Rule object property. When the user clicks "save" I use the parameters set in the view to build the ruleViewModel.Rule for each ruleViewModel they want to save, with porperties matching the GUI. The MainViewModel contains the DbContext object called dbo, so I use the ruleViewModel.Rule to write to the mainViewModel.dbo.Entry which I save to the Entity Framework. Here are the three basic steps performed for each saveable Rule View Model:
// get the rule from the GUI and use it to make sure we are updating the right rule in EF (which is connected to the mainViewModel)
var dboItem = ruleViewModel.MainViewModel.dbo.Rules.Single(r => r.Id == ruleViewModel.Rule.Id);
// set the values in the EF item to be those we got from the GUI
ruleViewModel.MainViewModel.dbo.Entry(dboItem).CurrentValues.SetValues(ruleViewModel.Rule);
// Save the differences
ruleViewModel.MainViewModel.dbo.SaveChanges();
If the user only saves a single rule, it all works fine, but if they subsequently try to save another, or if they save more than one at once, they get the following error, which is return by the ..SetValues(..) line:
Message = "The property 'Id' is part of the object's key information and cannot be modified. "
I see from other questions on this subject that there is a feature of EF that stops you from writing the same object twice to the database with a different Id, so this error often happens within a loop. I have tried using some of the suggestions, like adding
viewModel.MainViewModel.dbo.Rules.Add(dboItem);
and
viewModel.MainViewModel.dbo.Entry(dboItem).Property(x => x.Id).IsModified = false;
before the SaveChanges() command, but that has not helped with the problem (not to mention changing the function of the code). I see that some other suggestions say that the Entry should be created within the loop, but in this case, the entries are all existing rules in the database - it seems to me (perhaps erroneously) that I cannot create them inside the save loop, since they are the objects over which the loop is built - for each entity I find, I want to save changes.
I'm really confused about what to do and tying myself increasingly in knots trying to fix the error. It's been several days now and my sanity and self-esteem is beginning to wane! Any pointers to get me working in the right direction to stop the error appearing and allow me to set the database values would be really welcome as I feel like I have hit a complete dead end! The first time around the loop, everything works perfectly.
Aside from the questionable location of the DbContext and view models containing entities, this looks like it would work as expected. I'm assuming from the MVVM tag that this is a Windows application rather than a web app. The only issue is that this assumes that the Rule entity in your ruleViewModel is detached from the DbContext. If the DbContext is still tracking that entity reference then getting the entity from the DbContext again would pass you back the same reference.
It would probably be worth testing this once in a debug session. If you add the following:
var dboItem = ruleViewModel.MainViewModel.dbo.Rules.Single(r => r.Id == ruleViewModel.Rule.Id);
bool isReferenceSame = Object.ReferenceEquals(dboItem, ruleViewModel.Rule);
Do you get an isReferenceSame value of True or False? If True, the DbContext in your main view model is still tracking the Rule entity and the whole get dboItem and SetValues isn't necessary. If False, then the ruleViewModel is detached.
If the entities are attached and being tracked then edits to the view model entities would be persisted when you call a SaveChanges on the DbContext. (No load & SetValues needed) This should apply to single or multiple entity edits.
If the entities are detached then normally the approach for updating an entity across DbContext instances would look more like:
var context = mainViewModel.dbo;
foreach( var ruleViewModel in updatedRuleViewModels)
{
// This should associate the Entity in the ruleViewModel with the DbContext and set it's tracking state to Modified.
context.Entry(ruleViewModel.Rule).State = EntityState.Modified;
}
context.SaveChanges();
There are a couple of potential issues with this approach that you should consider avoiding if possible. A DbContext should be kept relatively short lived, so seeing a reference to a DbContext within a ViewModel is a bit of a red flag. Overall I don't recommend putting entity references inside view models or passing them around outside of the scope of the DbContext they were created in. EF certainly supports it, but it requires a bit more care and attention to assess whether entities are tracked or not, and in situations like web applications, opens the domain to invalid tampering. (Trusting the entity coming in where any change is attached or copied across overwriting the data state)

EF4 update a value for all rows in a table without doing a select

I need to reset a boolean field in a specific table before I run an update.
The table could have 1 million or so records and I'd prefer not to have to have to do a select before update as its taking too much time.
Basically what I need in code is to produce the following in TSQL
update tablename
set flag = false
where flag = true
I have some thing close to what I need here http://www.aneyfamily.com/terryandann/post/2008/04/Batch-Updates-and-Deletes-with-LINQ-to-SQL.aspx
but have yet to implement it but was wondering if there is a more standard way.
To keep within the restrictions we have for this project, we cant use SPROCs or directly write TSQL in an ExecuteStoreCommand parameter on the context which I believe you can do.
I'm aware that what I need to do may not be directly supported in EF4 and we may need to look at a SPROC for the job [in the total absence of any other way] but I just need to explore fully all possibilities first.
In an EF ideal world the call above to update the flag would be possible or alternatively it would be possible to get the entity with the id and the boolean flag only minus the associated entities and loop through the entity and set the flag and do a single SaveChanges call, but that may not be the way it works.
Any ideas,
Thanks in advance.
Liam
I would go to stakeholder who introduced restirctions about not using SQL or SProc directly and present him these facts:
Updates in ORM (like entity framework) work this way: you load object you perform modification you save object. That is the only valid way.
Obviously in you case it would mean load 1M entities and execute 1M updates separately (EF has no command batching - each command runs in its own roundtrip to DB) - usually absolutely useless solution.
The example you provided looks very interesting but it is for Linq-To-Sql. Not for Entity framework. Unless you implement it you can't be sure that it will work for EF, because infrastructure in EF is much more complex. So you can spent several man days by doing this without any result - this should be approved by stakeholder.
Solution with SProc or direct SQL will take you few minutes and it will simply work.
In both solution you will have to deal with another problem. If you already have materialized entities and you will run such command (via mentioned extension or via SQL) these changes will not be mirrored in already loaded entities - you will have to iterate them and set the flag.
Both scenarios break unit of work because some data changes are executed before unit of work is completed.
It is all about using the right tool for the right requirement.
Btw. loading of realted tables can be avoided. It is just about the query you run. Do not use Include and do not access navigation properties (in case of lazy loading) and you will not load relation.
It is possible to select only Id (via projection), create dummy entity (set only id and and flag to true) and execute only updates of flag but it will still execute up to 1M updates.
using(var myContext = new MyContext(connectionString))
{
var query = from o in myContext.MyEntities
where o.Flag == false
select o.Id;
foreach (var id in query)
{
var entity = new MyEntity
{
Id = id,
Flag = true
};
myContext.Attach(entity);
myContext.ObjectStateManager.GetObjectStateEntry(entity).SetModifiedProperty("Flag");
}
myContext.SaveChanges();
}
Moreover it will only work in empty object context (or at least no entity from updated table can be attached to context). So in some scenarios running this before other updates will require two ObjectContext instances = manually sharing DbConnection or two database connections and in case of transactions = distributed transaction and another performance hit.
Make a new EF model, and only add the one Table you need to make the update on. This way, all of the joins don't occur. This will greatly speed up your processing.
ObjectContext.ExecuteStoreCommand ( _
commandText As String, _
ParamArray parameters As Object() _
) As Integer
http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.executestorecommand.aspx
Edit
Sorry, did not read the post all the way.

LINQ to SQL disconnected updating object from different data context

Link
I'm using ASP.NET with C# and trying to use linq to sql to update a data context as exhibited on the blog linked above. I created the timestamp field in the table just as stated and am using the following method:
private void updateRecord(TableName updatedRecord)
{
context db = new context();
db.TableName.Attach(updatedRecord,true);
db.SubmitChanges();
}
My question is, are you supposed to assign the timeStamp field to anything in your updatedRecord before trying to call the Attach method on your data context?
When I run this code I get the following exception: System.Data.Linq.ChangeConflictException: Row not found or changed. I update all of the fields, including the primary key of the record that I'm updating before passing the object to this update method. During debugging the TimeStamp attribute of the object shows as null. I'm not sure if it's supposed to be that way or not.
Every book and resource I have says that this is the way to do it, but none of them go into great detail about this TimeStamp attribute.
I know this is quick and easy, so if anybody knows, please let me know.
Since you say that you created the time stamp field in the table, I wonder if, in the case where this column was added later, the column properties may not be set correctly.
You may want to check the properties on your TimeStamp column in the DBML designer. Make sure that:
AutoGenerated = true
Auto-Sync = Always
Time Stamp = True
Update Check = Never
The server data type should be rowversion NOT NULL
If it is not set to be auto generated and synced always, the row version won't be returned from the insert since you haven't changed it when the insert was done. Even though this value is generated by the database the DataContext needs to know this so that it can handle it properly.
In addition, now that you have a timestamp column, UpdateCheck should be set to Never for all of the other columns.
If you have a timestamp column, then to update a record (from a vanilla object): yes, I would expect to have to assign it. Otherwise, you lose the ability to use the timestamp for optimistic concurrency checking.
The idea is you take a copy of the timestamp when you get hold of your (disconnected) object, then when you update you can use this column to verify that nobody else has edited the row.
There are two common scenarios:
1: if you are only performing a short lived operation, get the record out of the database first - make your changes to the object, and simply SumbitChanges() [all with the same data-context]. The data-context will handle concurrency for you.
2: if you are disconnecting the object (for example passing it to a client application for a while), then use something like serialization (LINQ-to-SQL objects support DataContractSerializer (optionally; you need to enable it)). So serialize the object at the server, pass it to the client - the client makes changes to their copy and passes it back. The server deserializes it and uses Attach() and SubmitChanges(). The record in memory should still have the timestamp that it had when extracted from the database, so we can perform optimistic concurrency spanning all the time the record has been disconnected.

Categories