Asp.net mvc 3 实体框架乐观并发异常未发生
我们有一个ASP.Net MVC应用程序,它使用EF4作为其数据访问层,我们看到了与OptimisitcConcurrencyException相关的意外行为,而不是在我们认为应该抛出异常时抛出异常 我们已将问题简化为以下代码Asp.net mvc 3 实体框架乐观并发异常未发生,asp.net-mvc-3,entity-framework-4,optimistic-concurrency,Asp.net Mvc 3,Entity Framework 4,Optimistic Concurrency,我们有一个ASP.Net MVC应用程序,它使用EF4作为其数据访问层,我们看到了与OptimisitcConcurrencyException相关的意外行为,而不是在我们认为应该抛出异常时抛出异常 我们已将问题简化为以下代码 using System.Linq; using Project.Model; namespace OptimisticConcurrency { class Program { st
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子句中使用的是版本,但使用的是thirdEntities版本值(数据库中的当前值),而不是firstEntities值,尽管它在调用SaveChanges之前被显式设置。SaveChanges正在将版本重置为检索到的值而不是设置值
在EDMX中,将版本设置为具有StoreGeneratedPattern,并将其设置为Computed
有人知道这里发生了什么吗?这是个问题。一旦该列设置为
Computed
,则无法在应用程序中设置其值(可以,但不使用该值)
编辑:
若从数据库加载实体,则默认情况下会使用上下文跟踪该实体。上下文存储其原始值。例如,原始值用于快照更改跟踪,但它们也用作计算属性的唯一有效来源。如果在实体中设置了Computed
属性,则不使用该值,而是使用原始值。解决方法是修改原始值(在修改任何其他值之前):
编辑2:
顺便说一句。一旦您实际加载了时间戳和以前检索到的时间戳,您就可以简单地代替在数据库中执行此操作。当我将版本列设置为StoreGeneratedPattern=None时,我会收到一个异常,说我无法更新数据库中的时间戳列。是的,此行为完全不起作用。我将在晚上尝试一种解决方法,并让您知道。
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();
}