Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework DB First: Timestamp column not working

Using db first approach, I want my application to throw a concurrency exception whenever I try to update an (out-of-date) entity which it's correspoinding row in the database has been already updated by another application/user/session.

I am using Entity Framework 5 on .Net 4.5. The corresponding table has a Timestamp column to maintain row version.

like image 385
Alireza Avatar asked Aug 22 '13 15:08

Alireza


2 Answers

I have done this in the past by adding a timestamp field to the table you wish to perform a concurrency check. (in my example i added a column called ConcurrencyCheck)

There are two types of concurrency mode here depending on your needs :

1 Concurrency Mode: Fixed :

Then re-add/refresh your table in your model. For fixed concurrency , make sure your set your concurrency mode to fixed for your table when you import it into your model : like this :

enter image description here

Then to trap this :

    try 

    { 

    context.SaveChanges(); 

    } 

    catch (OptimisticConcurrencyException ex) { 


////handle your exception here...

2. Concurrency Mode: None

If you wish to handle your own concurrency checking , i.e. raise a validation informing the user and not even allowing a save to occur then you can set Concurrency mode None.

1.Ensure you change the ConcurrencyMode in the properties of the new column you just added to "None". 2. To use this in your code , i would create a variable to store your current timestamp on the screen you which to check a save on.

private byte[] CurrentRecordTimestamp 
        { 
            get 
            { 
                return (byte[])Session["currentRecordTimestamp"]; 
            } 

            set 
            { 
                Session["currentRecordTimestamp"] = value; 

            } 
        }

1.On page load (assuming you're using asp.net and not mvc/razor you dont mention above), or when you populate the screen with the data you wish you edit , i would pull out the current record under edit's ConcurrencyCheck value into this variable you created.

 this.CurrentRecordTimestamp = currentAccount.ConcurrencyCheck;

Then if the user leaves the record open , and someone else in the meantime changes it , and then they also attempt to save , you can compare this timestamp value you saved earlier with the concurrency value it is now.

if (Convert.ToBase64String(accountDetails.ConcurrencyCheck) != Convert.ToBase64String(this.CurrentRecordTimestamp)) 
{ 
} 
like image 118
Alicia Avatar answered Nov 14 '22 13:11

Alicia


After reviewing many posts here and on the web explaining concurrency and timestamp in Entity Framework 5, I came into the conclusion that basically it is impossible to get a concurrency exception when the model is generated from an existing database.

One workaround is modifying the generated entities in the .edmx file and setting the "Concurrency Mode" of the entity's timestamp property to "Fixed". Unfortunately, if the model is repeatedly re-generated from the database this modification may be lost.

However, there is one tricky workaround:

  1. Initialize a transaction scope with isolation level of Repeatable Read or higher

  2. Get the timestamp of the row

  3. Compare the new timestamp with the old one

  4. Not equal --> Exception

  5. Equal --> Commit the transaction

The isolation level is important to prevent concurrent modifications of inferring.

PS: Erikset's solution seems to be fine to overcome regenerating the model file.

like image 5
Alireza Avatar answered Nov 14 '22 15:11

Alireza