使用 db first 方法,我希望我的应用程序在我尝试更新一个(过期的)实体时抛出一个并发异常,它在数据库中对应的行已经被另一个应用程序/用户/会话更新。
我在 .Net 4.5 上使用实体框架 5。对应的表有一个 Timestamp 列来维护行版本。
使用 db first 方法,我希望我的应用程序在我尝试更新一个(过期的)实体时抛出一个并发异常,它在数据库中对应的行已经被另一个应用程序/用户/会话更新。
我在 .Net 4.5 上使用实体框架 5。对应的表有一个 Timestamp 列来维护行版本。
我过去通过向您希望执行并发检查的表添加时间戳字段来完成此操作。(在我的示例中,我添加了一个名为 ConcurrencyCheck 的列)
根据您的需要,这里有两种并发模式:
1 并发模式:固定:
然后在模型中重新添加/刷新您的表格。对于固定并发,请确保在将表导入模型时将并发模式设置为固定:如下所示:
然后捕获这个:
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))
{
}
在查看了此处和 Web 上许多解释 Entity Framework 5 中的并发和时间戳的帖子后,我得出的结论是,当模型从现有数据库生成时,基本上不可能出现并发异常。
一种解决方法是修改 .edmx 文件中生成的实体并将实体的时间戳属性的“并发模式”设置为“固定”。不幸的是,如果模型反复从数据库中重新生成,这种修改可能会丢失。
但是,有一个棘手的解决方法:
使用可重复读取或更高的隔离级别初始化事务范围
获取行的时间戳
将新时间戳与旧时间戳进行比较
不等于 --> 异常
相等 --> 提交事务
隔离级别对于防止并发修改推断很重要。
PS: Erikset 的解决方案似乎很好地克服了重新生成模型文件。
如果没有行受到影响,EF 会检测到并发冲突。然后,如果您使用存储过程来删除和更新,您可以在 where 子句中手动添加时间戳值:
UPDATE | DELETE ... WHERE PKfield = PkValue and Rowversionfield = rowVersionValue
然后,如果该行已被其他任何人删除或修改,则 Sql 语句会影响 0 行,EF 将其解释为并发冲突。