在Entity Framework中使用存储过程实现乐观并发控制

5
在实体框架中,使用存储过程进行乐观并发的表更新操作。我一直无法使其正常工作,而不修改现有的更新存储过程。我正在尝试确定是否有一种方法可以映射我的现有存储过程,以便在没有更新任何行时出现并发异常。
一些背景信息:
  • I've mapped the update stored procedure (including the timestamp) column in my .edmx file
  • My existing stored procedure looks like the following (the actual table names and columns are obviously omitted):

    UPDATE Table SET Column = @Column1, Column2 = @Column2 ....
    WHERE PK = @PK AND Timestamp = @Timestamp
    
    SELECT PK, Column1, Column2, ....., Timestamp
    FROM Table WHERE PK = @PK
    
  • In the event that the update fails (due to a timestamp mismatch) the select portion of the stored procedure will still return a row.

当我将存储过程修改为以下内容时:
   UPDATE Table SET Column = @Column1, Column2 = @Column2 ....
   WHERE PK = @PK AND Timestamp = @Timestamp

   IF @@ROWCOUNT > 0
       SELECT PK, Column1, Column2, ....., Timestamp
       FROM Table WHERE PK = @PK

然后一切按预期进行,并发错误就会发生。

或者,如果我使存储过程返回一个输出参数,并将该输出参数映射到 Entity Framework 的 .edmx 文件中的“Rows Affected Parameter”,那么并发错误也将按预期工作。

我发现,这种解决方案(即使用输出参数)在这里得到了最好的解释:http://petermannerhult.wordpress.com/2010/10/01/entity-framework-4-with-optimistic-concurrency-and-stored-procedures/

然而,以上两个步骤似乎都不应该是必要的,因为我认为Entity Framework可以只使用更新的行数来确定是否应引发并发异常。我在 ADO.NET 数据集中使用这些完全相同的存储过程(使用乐观并发),没有任何问题。所以我的问题是,如何在不修改现有存储过程的情况下,使用这些存储过程启用 Entity Framework 中的乐观并发?


2
我认为这并不是EF的问题。EF无法访问存储过程内部的更新语句的行数。所以你需要在存储过程内部检查rowcount或者将行数从存储过程返回,这样EF才能确定该行是否已经被更新。 - Satish
@Satish 感谢您的回复,但是您能解释一下为什么 EF 无法访问我的更新语句的行数吗?当在 SQL Server 中执行存储过程时,应该可以获得此信息。例如,可以使用 SqlDataReader 的 RecordsAffected 属性访问它(请参见 http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.recordsaffected.aspx)。鉴于这个确切的存储过程在 ADO.NET 中可以工作(使用乐观并发),必须有可能确定更新的行数。EF 不能做到这一点的原因是什么? - actf
1
看起来 EF 无法自行从存储过程执行中获取 RecordsAffected 属性。我可以猜测各种可能的原因,但最终只有 EF 产品开发人员才能确定。而且为什么会这样并不重要,重要的是它就是不能这样工作。 - RBarryYoung
1
@RBarryYoung 是的,不幸的是我认为你可能是正确的。这也是我得出的结论。似乎修改我的存储过程是使其工作的唯一方法 :-( - actf
1
同意。由于“OUTPUT”参数也可以是可选的存储过程参数,因此您应该能够在不更改任何其他调用代码的情况下添加它。 - RBarryYoung
显示剩余2条评论
2个回答

0
在EDMX设计器的存储过程映射窗口中,每个属性旁边都有两个复选框。一个是“使用原始值”,另一个是“行受影响参数”。正如您所指出的,“行受影响参数”需要您在存储过程中使用输出参数。但是,如果您为时间戳选择“使用原始值”,它会将它们进行比较,并在两者不匹配时抛出“OptimisticConcurrencyException”异常。这应该允许您在不修改存储过程的情况下获取异常。

-1

如果您真的不想更改存储过程代码,可以将从存储过程返回的时间戳与传入的时间戳进行比较。如果不同,则表示存在并发错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接