Concurrency 实体框架数据库优先:时间戳列不工作

Concurrency 实体框架数据库优先:时间戳列不工作,concurrency,timestamp,entity-framework-5,Concurrency,Timestamp,Entity Framework 5,使用db first方法,每当我尝试更新数据库中与其对应的行已由另一个应用程序/用户/会话更新的(过期)实体时,我希望我的应用程序抛出并发异常 我正在使用.NET4.5上的EntityFramework5。对应的表有一个时间戳列来维护行版本。在查看了这里和web上解释Entity Framework 5中并发性和时间戳的许多帖子后,我得出结论,当模型从现有数据库生成时,基本上不可能获得并发异常 一种解决方法是修改.edmx文件中生成的实体,并将实体的时间戳属性的“并发模式”设置为“固定”。不幸的

使用db first方法,每当我尝试更新数据库中与其对应的行已由另一个应用程序/用户/会话更新的(过期)实体时,我希望我的应用程序抛出并发异常


我正在使用.NET4.5上的EntityFramework5。对应的表有一个时间戳列来维护行版本。

在查看了这里和web上解释Entity Framework 5中并发性和时间戳的许多帖子后,我得出结论,当模型从现有数据库生成时,基本上不可能获得并发异常

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

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

  • 初始化隔离级别为Repeatable Read或更高的事务作用域

  • 获取行的时间戳

  • 将新的时间戳与旧的时间戳进行比较

  • 不等于-->异常

  • 相等-->提交事务

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

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

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

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

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

    我以前通过向要执行并发检查的表中添加时间戳字段来实现这一点。(在我的示例中,我添加了一个名为ConcurrencyCheck的列)

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

    1并发模式:修复:

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

    那么,为了解决这个问题:

        try 
    
        { 
    
        context.SaveChanges(); 
    
        } 
    
        catch (OptimisticConcurrencyException ex) { 
    
    
    ////handle your exception here...
    
    2。并发模式:无

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

    1.确保更改刚刚添加到“无”的新列的属性中的并发模式 2.为了在代码中使用它,我将创建一个变量,将当前时间戳存储在屏幕上,以检查是否保存

    private byte[] CurrentRecordTimestamp 
            { 
                get 
                { 
                    return (byte[])Session["currentRecordTimestamp"]; 
                } 
    
                set 
                { 
                    Session["currentRecordTimestamp"] = value; 
    
                } 
            }
    
    1.在页面加载时(假设您使用的是asp.net,而不是上面没有提到的mvc/razor),或者当您在屏幕上填充希望编辑的数据时,我会将edit的ConcurrencyCheck值下的当前记录拖到您创建的这个变量中

     this.CurrentRecordTimestamp = currentAccount.ConcurrencyCheck;
    
    然后,如果用户让记录保持打开状态,同时其他人更改了它,然后他们也尝试保存,则可以将先前保存的时间戳值与现在的并发值进行比较

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

    虽然您是对的,但首先,使用存储过程执行NaitiveSQL与EF没有(直接)关系。其次,我要说的是通过调用context.SaveChanges()更新实体,您可以将存储过程附加到entty,然后在调用SaveChanges时,EF将为您调用正确的存储过程。如果sp未更新任何行,您将获得并发例外。请发布一行代码,说明如何将存储过程附加到实体以进行更新。在EF designer中:1:创建存储过程2:从数据库更新模型并包含存储过程3:单击实体并转到“映射详细信息”在“映射详细信息窗口”的右上角,单击“将实体映射到函数”,然后选择实体的插入、删除和更新存储过程。给我一点时间,我会发布每个步骤的一些屏幕截图。圣地亚哥,我应该再次说,如果模型重新生成,手动修改将丢失。是否有可能保证当模型重新生成时,修改会通过某种技巧恢复?这个解决方法是我在自己的回答中已经指出的。它的缺点是,每当重新创建.edmx文件时,修改都会自动丢失。这会导致什么错误?”“无”适用于我的解决方案中的上述场景。如果您遵循我上面的示例,它可以正常工作。我已经在一个实时系统中实施了12个月,没有任何问题。我澄清:第二个解决方案仅在考虑某个应用程序空间中的并发更改时才有效。例如,如果您在Management Studio中运行查询以修改行,则解决方案将失败。此外,在您的解决方案中,时间戳的值应存储在比会话范围更广的位置。如果并发修改是在另一台机器上进行的,该怎么办?@Alireza难道你不能创建一个
    元数据类型
    ,这样当你修改你的EDMX时属性就不会丢失吗?我对这个问题的回答是:提供一个控制台应用程序,它可以自动查找时间戳属性并在中设置并发模式您的edmx文件。您可以将其作为预构建步骤来运行,以自动化流程。不幸的是,我认为您是对的。虽然有一个工作项计划在将来的版本中发布,但是没有自动执行的方法。我做的和@Erikest一样。创建了一个控制台应用程序,它读取XML以在所有表上设置并发模式,并将我的概念模型的主键重命名为“ID”,以便我的POCO模型可以共享一个公共接口。我添加了一个控制台