实体框架数据库首先:时间戳列不起作用

时间:2013-08-22 15:06:00

标签: concurrency timestamp entity-framework-5

使用db first方法,我希望我的应用程序在每次尝试更新(过时的)实体时抛出并发异常,该实体已经由另一个应用程序/用户/会话更新了数据库中的相应行。

我在.Net 4.5上使用Entity Framework 5。相应的表有一个Timestamp列来维护行版本。

3 个答案:

答案 0 :(得分:11)

我过去通过在您希望执行并发检查的表中添加时间戳字段来完成此操作。 (在我的例子中,我添加了一个名为ConcurrencyCheck的列)

根据您的需要,这里有两种类型的并发模式:

1并发模式:已修复:

然后在模型中重新添加/刷新您的表格。对于固定并发,请确保在将其导入模型时将表的并发模式设置为固定:如下所示:

enter image description here

然后陷阱:

    try 

    { 

    context.SaveChanges(); 

    } 

    catch (OptimisticConcurrencyException ex) { 


////handle your exception here...

<强> 2。并发模式:无

如果您希望处理自己的并发检查,即提出通知用户的验证,甚至不允许进行保存,那么您可以将并发模式设置为无。

1.确保在刚刚添加到“无”的新列的属性中更改 ConcurrencyMode  2.要在代码中使用它,我会创建一个变量来将当前时间戳存储在要检查保存的屏幕上。

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

            set 
            { 
                Session["currentRecordTimestamp"] = value; 

            } 
        }

1.在页面加载时(假设您使用的是asp.net而不是mvc / razor,上面没有提及),或者当您使用您希望编辑的数据填充屏幕时,我会将当前记录拉出来将ConcurrencyCheck值编辑到您创建的此变量中。

 this.CurrentRecordTimestamp = currentAccount.ConcurrencyCheck;

然后,如果用户打开记​​录,同时其他人更改记录,然后他们也尝试保存,您可以将之前保存的时间戳值与现在的并发值进行比较。

if (Convert.ToBase64String(accountDetails.ConcurrencyCheck) != Convert.ToBase64String(this.CurrentRecordTimestamp)) 
{ 
} 

答案 1 :(得分:5)

在回顾了这里和网上解释实体框架5中的并发性和时间戳的许多帖子之后,我得出的结论是,当从现有数据库生成模型时,基本上不可能获得并发异常。

一种解决方法是修改.edmx文件中生成的实体,并将实体的timestamp属性的“Concurrency Mode”设置为“Fixed”。不幸的是,如果从数据库重复生成模型,则此修改可能会丢失。

但是,有一个棘手的解决方法:

  1. 使用可重复读取或更高版本的隔离级别初始化事务范围

  2. 获取行的时间戳

  3. 将新时间戳与旧时间戳进行比较

  4. 不相等 - &gt;例外

  5. 等于 - &gt;提交交易

  6. 隔离级别对于防止推断的并发修改非常重要。

    <强> PS: Erikset的解决方案似乎可以克服重新生成模型文件。

答案 2 :(得分:0)

如果没有行受影响,EF会检测到并发冲突。然后,如果使用存储过程进行删除和更新,则可以在where子句中手动添加时间戳值:

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

然后,如果该行已被其他任何人删除或修改,则Sql语句会影响0行,EF会将其解释为并发冲突。