Entity Framework DB First: Timestamp column not working

て烟熏妆下的殇ゞ 提交于 2019-12-05 08:35:20

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 :

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)) 
{ 
} 

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.

EF detects a concurrency conflict if no rows were affected. Then if you use stored procedures to delete and update you could manually add the timestamp value in the where clause:

UPDATE | DELETE ... WHERE PKfield = PkValue and Rowversionfield = rowVersionValue

Then if the row has been deleted or modified by anyone else the Sql statement affects 0 rows and EF interpret it as concurrency conflict.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!