使用EF DbContext。我的实体对象有rowversion列(SQL Compact版本4),用于并发检查(ConcurrencyMode = Fixed,StoreGeneratedPattern = Computed)。
为了强制并发异常,我从UI中以2种不同的形式读取相同的表记录,编辑每个表,然后一个接一个地保存。以下代码执行实际的保存操作。
单击第二个表单上的保存按钮时,会出现预期的并发错误。然而, 从数据库复制原始值后,异常仍然在第二次尝试时仍然存在。只有第三次尝试成功,没有任何错误。有人可以解释一下可能导致这个问题的原因吗?
try
{
_ctx.SaveChanges(); //first attempt
}
catch (Exception ex)
{
if (ex is DbUpdateConcurrencyException)
{
var exc = ex as DbUpdateConcurrencyException;
foreach (var entry in exc.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
try
{
_ctx.SaveChanges(); //second attempt
}
catch (Exception ex2)
{
if (ex2 is DbUpdateConcurrencyException)
{
var exc2 = ex2 as DbUpdateConcurrencyException;
foreach (var entry in exc2.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
try
{
_ctx.SaveChanges(); //third attempt
}
catch (Exception ex3)
{
System.Windows.MessageBox.Show(ex3.Message);
}
}
}
}
}
编辑:我发现当我通过UI进行两次更新时都会发生这种情况。如果在上面的代码中,在第一次尝试之前,我会执行以下操作:
var _ctx2 = new MyDbContext();
var myEntity = _ctx2.MyEntities.Where(ent => ent.Id == 2).Single();
myEntity.Name = "My new name";
_ctx2.SaveChanges();
_ctx2.Dispose();
然后代码按预期工作,因为myEntity的另一个实例是通过UI更新的;即第二次尝试将拯救myEntity。 而且,问题在于以下几行:
foreach (var entry in exc.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
因为,当通过UI更新时,exc.Entries不返回发生并发错误的实体,而是返回其导航属性实体。
在这种情况下,MyEntity是一个类似树的自引用实体,它有两个导航属性:ParentEntity和Children。
因此,在第一次保存尝试之后,我在exc.Entries中拥有的是ParentEntity(处于未更改状态),并且仅在第二次保存尝试之后,exc.Entries返回引发并发错误的实际实体。
答案 0 :(得分:1)
好吧,这似乎是一个EF错误。请参阅以下内容:
http://support.microsoft.com/kb/2390624#appliesto
http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/ce60bf40-cd05-42f6-ab8f-26b048ec83d7