5

我们有一个使用EF4作为其数据访问层的ASP.Net MVC应用程序,并且我们发现OptimisitcConcurrencyExceptions在我们认为它们应该出现时不会引发意外行为。实体框架乐观并发异常没有发生

我们已经简化了问题,下到下面的代码...

using System.Linq; 
    using Project.Model; 

    namespace OptimisticConcurrency 
    { 
     class Program 
     { 
      static void Main() 
      { 
       Contact firstContact = null; 
       using (var firstEntities = new ProjectEntities()) 
       { 
        firstContact = (from c in firstEntities.Contacts 
         where c.LastName == "smith" select c).Single(); 
       } 

       using (var secondEntities = new ProjectEntities()) 
       { 
        var secondContact = (from c in secondEntities.Contacts 
         where c.LastName == "smith" select c).Single(); 

        secondContact.Title = "a"; 
        secondEntities.SaveChanges(); 
       } 

       firstContact.Title = "b"; 

       using (var thirdEntities = new ProjectEntities()) 
       { 
        var thirdContact = (from c in thirdEntities.Contacts 
         where c.LastName == "smith" select c).Single(); 

        thirdContact.Title = firstContact.Title; 

        //EXPLICITLY SET VERSION HERE 
        thirdContact.Version = firstContact.Version; 

        thirdEntities.SaveChanges(); 
       } 
      } 
     } 
    } 

这是在我们的MVC应用程序会发生什么一个相当简单的版本,但同样的问题出现。

当我们在第三实体上调用SaveChanges时,我期待异常并没有被抛出。

更有趣的是,当我们连接SQL事件探查器时,我们看到版本在where子句中使用,但它是第三实体版本值(当前在数据库中)正在使用,而不是firstEntities值DESPITE它在调用SaveChanges之前立即明确设置。 SaveChanges将版本重置为检索值而不是设置值。

在EDMX中,Version设置为将StoreGeneratedPattern设置为Computed。

任何人都知道这里发生了什么?

回答

9

这是一个问题。将列设置为Computed后,您无法在应用程序中设置其值(您可以但未使用此值)。

编辑:

如果从数据库中加载实体是默认与上下文跟踪。上下文存储其原始值。原始值例如用于快照更改跟踪,但它们也被用作Computed属性的唯一有效来源。如果您在实体中设置Computed属性,则不会使用该值,并将原始值用于insted。解决方法是修改原来的值(修改任何其他事情之前):

using (var context = new TestEntities()) 
{ 
    var entityToUpdate = context.MyEntities.Single(e => e.Id == someId); 
    entityToUpdate.Timestamp = entity.Timestamp; 

    ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate); 
    entry.ApplyOriginalValues(entityToUpdate); 

    // set modified properties 
    context.SaveChanges(); 
} 

编辑2:

顺便说一句。一旦你有两个实际加载时间戳和以前检索的时间戳,你可以简单地compare them in your application,而不是在数据库中。

+1

当我将Version列设置为StoreGeneratedPattern = None时,我收到一个异常,说我无法更新数据库中的时间戳列。 – 2011-03-16 16:03:57

+0

是的,这种行为完全不起作用。我会在晚上尝试一种解决方法并让你知道。 – 2011-03-16 16:46:57