我在使用Update存储过程理解并发性问题时遇到了一些困难。我遵循Julie Lerman的编程实体框架,她在一个例子中给出了以下代码:
using (var context = new BAEntities())
{
var payment = context.Payments.First();
if (payment.PaymentDate != null)
{
payment.PaymentDate = payment.PaymentDate.Value.AddDays(1);
}
var origRowVersion = payment.RowVersion;
try
{ //BREAKPOINT #1
context.SaveChanges();
var newRowVersion = payment.RowVersion;
if (newRowVersion == origRowVersion)
{
Console.WriteLine("RowVersion not updated");
}
else
{
Console.WriteLine("RowVersion updated");
}
}
catch (OptimisticConcurrencyException)
{
Console.WriteLine("Concurrency Exception was thrown");
}
}
更新SP如下:
UPDATE payments
SET paymentdate=@date,reservationID=@reservationID,amount=@amount, modifieddate=@modifiedDate
WHERE
paymentid=@paymentid AND ROWVERSION=@rowversion
IF @@ROWCOUNT>0
SELECT RowVersion AS newTimeStamp FROM payments WHERE paymentid=@paymentid
和"使用原始值"复选框在映射中被选中,看起来像这样:https://dl.dropboxusercontent.com/u/135754/updatemapping.png
现在,当我尝试:
按原样运行代码,然后在调试器中检查的newRowVersion与origRowversion相同,但应用程序进入'else'子句(为什么它首先是相同的,我刚刚改变了它?
运行代码,但在breakpoint# 1中,我更新了Management Studio中的支付对象,SaveChanges抛出了OptimisticConcurrencyException。
每次当我查看SQL Profiler时,原始版本的时间戳都被发送到服务器。
然后,当我在SP映射中为时间戳值勾选"使用原始值"时,一切都以上述方式工作…我不明白这是怎么回事。我测试错了吗?什么时候应用程序应该进入'if'子句?
提前感谢,干杯!
编辑:我添加了newTimeStamp作为Update SP映射的返回值。现在我可以看到RowVersion的更新值正确地从DB中获取。但是我还是看不出选中"Use original value"和不选中"Use original value"有什么区别。
我想我现在明白了。当我尝试在调用savechanges之前手动更改rowversion(为随机字节[])时:
- 使用未检查的原始值:'随机字节[]'被发送到DB并在更新存储过程中使用(在WHERE子句中),导致OptimisticConcurrencyException
- 使用原始值检查:rowversion最初从DB下载时的值被发送并用于更新存储过程(在WHERE子句中)
我猜这就是使用原始值的目的…这对我来说有点奇怪,谁会在同一个上下文中手动更改它?