OptimisticConcurrencyException不实体框架的工作在某些情况下 [英] OptimisticConcurrencyException Does Not Work in Entity Framework In Certain Situations

查看:207
本文介绍了OptimisticConcurrencyException不实体框架的工作在某些情况下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新(2010-12-21):完全改写了基于我一直在做测试这个问题。此外,这曾经是一个POCO具体问题,但事实证明,我的问题是不一定特定POCO

我使用实体框架和我有我的数据库表中的时间戳列应该用于跟踪乐观并发的变化。我给自己定的并发模式该属性的实体设计,以固定而我得到不一致的结果。这里有一对夫妇以证实并发检查在一个场景的作品,但不是在另一幅简化方案。

I'm using Entity Framework and I've got a timestamp column in my database table that should be used to track changes for optimistic concurrency. I've set the concurrency mode for this property in the Entity Designer to "Fixed" and I'm getting inconsistent results. Here are a couple of simplified scenarios that demonstrate that concurrency checking works in one scenario but not in another.

成功抛出OptimisticConcurrencyException:

如果我附上一个断开连接的实体,然后调用SaveChanges将抛出OptimisticConcurrencyException如果有一个时间戳冲突:

If I attach a disconnected entity, then SaveChanges will throw an OptimisticConcurrencyException if there is a timestamp conflict:

    [HttpPost]
    public ActionResult Index(Person person) {
        _context.People.Attach(person);
        var state = _context.ObjectStateManager.GetObjectStateEntry(person);
        state.ChangeState(System.Data.EntityState.Modified);
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

不抛出OptimisticConcurrencyException:

在另一方面,如果我从数据库中检索我的实体的新副本,我做了一些领域的部分更新,然后调用调用SaveChanges(),那么即使有时间戳冲突,我不知道得到OptimisticConcurrencyException:

On the other hand, if I retrieve a new copy of my entity from the database and I do a partial update on some fields, and then call SaveChanges(), then even though there is a timestamp conflict, I don't get an OptimisticConcurrencyException:

    [HttpPost]
    public ActionResult Index(Person person) {
        var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
        currentPerson.Name = person.Name;

        // currentPerson.VerColm == [0,0,0,0,0,0,15,167]
        // person.VerColm == [0,0,0,0,0,0,15,166]
        currentPerson.VerColm = person.VerColm;

        // in POCO, currentPerson.VerColm == [0,0,0,0,0,0,15,166]
        // in non-POCO, currentPerson.VerColm doesn't change and is still [0,0,0,0,0,0,15,167]
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

根据SQL事件探查器,它看起来像实体框架是忽略了新VerColm(这是timestamp属性),而是使用原来装VerColm。正因为如此,它绝不会抛出OptimisticConcurrencyException

Based on SQL Profiler, it looks like Entity Framework is ignoring the new VerColm (which is the timestamp property) and instead using the originally loaded VerColm. Because of this, it will never throw an OptimisticConcurrencyException.

更新:增加每人一月的请求的其他信息:

请注意,我还添加了注释上述code与我在我的控制器动作看通过这个例子工作时一致。

Note that I also added comments to the above code to coincide with what I see in my controller action while working through this example.

这是VerColm在我的数据库中的值之前更新:0x0000000000000FA7

This is the value of the VerColm in my DataBase prior to the update: 0x0000000000000FA7

下面是SQL事件探查器显示在做更新时:

Here is what SQL Profiler shows when doing the update:

exec sp_executesql N'update [dbo].[People]
set [Name] = @0
where (([Id] = @1) and ([VerColm] = @2))
select [VerColm]
from [dbo].[People]
where @@ROWCOUNT > 0 and [Id] = @1',N'@0 nvarchar(50),@1 int,@2 binary(8)',@0=N'hello',@1=1,@2=0x0000000000000FA7

注意@ 2应该已经0x0000000000000FA6,但它的0x0000000000000FA7

Note that @2 should have been 0x0000000000000FA6, but it's 0x0000000000000FA7

下面是VerColm在更新后,我的数据库:0x0000000000000FA8

Here is the VerColm in my DataBase after the update: 0x0000000000000FA8

有谁知道我怎么能解决这个问题呢?我想实体框架抛出一个异常,当我更新现有实体,并有一个时间戳冲突。

Does anyone know how I can work around this problem? I'd like Entity Framework to throw an exception when I update an existing entity and there's a timestamp conflict.

感谢

推荐答案

说明

为什么你没有得到的原因预期的 OptimisticConcurrencyException 关于你的第二个code的例子是,由于方式EF检查并发:

The reason why you aren't getting the expected OptimisticConcurrencyException on your second code example is due to the manner EF checks concurrency:

当您检索通过查询你的数据库实体,EF记住所有的值与 ConcurrencyMode.Fixed 通过查询作为原始,未经修改的值的时间标记属性。

When you retrieve entities by querying your db, EF remembers the value of all with ConcurrencyMode.Fixed marked properties by the time of querying as the original, unmodified values.

然后你改变一些属性(包括固定标记的)并调用的SaveChanges()您的DataContext。

Then you change some properties (including the Fixed marked ones) and call SaveChanges() on your DataContext.

通过比较所有的当前值并发更新EF检查固定标记分贝列与固定的原始的,未经修改的值标记属性。
这里的关键点是,EF对待你的更新时间戳属性作为的正常的数据属性更新。您所看到的行为是由设计。

EF checks for concurrent updates by comparing the current values of all Fixed marked db columns with the original, unmodified values of the Fixed marked properties. The key point here is that EF treats the update of you timestamp property as a normal data property update. The behavior you see is by design.

解决方案/解决方法

要解决,你有以下几种选择:

To workaround you have the following options:


  1. 使用您的第一个办法:不要重新查询该数据库对你的实体,但重新实体连接到您的上下文

  1. Use your first approach: Don't requery the db for your entity but Attach the recreated entity to your context.

假的时间戳值是当前dB值,使EF并发检查使用您提供的值如下所示(见<一href=\"http://stackoverflow.com/questions/2775450/asp-net-mvc-concurrency-with-rowversion-in-edit-action/2775887#2775887\">this回答一个类似的问题):

Fake your timestamp value to be the current db value, so that the EF concurrency check uses your supplied value like shown below (see also this answer on a similar question):

var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
currentPerson.VerColm = person.VerColm; // set timestamp value
var ose = _context.ObjectStateManager.GetObjectStateEntry(currentPerson);
ose.AcceptChanges();       // pretend object is unchanged
currentPerson.Name = person.Name; // assign other data properties
_context.SaveChanges();


  • 您可以通过您的时间戳值进行比较的重新查询时间戳值检查并发自己:

  • You can check for concurrency yourself by comparing your timestamp value to the requeried timestamp value:

    var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
    if (currentPerson.VerColm != person.VerColm)
    {
        throw new OptimisticConcurrencyException();
    }
    currentPerson.Name = person.Name; // assign other data properties
    _context.SaveChanges();
    


  • 这篇关于OptimisticConcurrencyException不实体框架的工作在某些情况下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆