开发者

Cannot update an object using Entity Framework with Concurrency Fixed enabled

I will be more specific here.. This is a strange problem and really, i am not understanding why this is happening..

In my data model every table has a column of type rowversion, and in my EDM (Entity Data Model) i enabled version to be my rowversion and maps exacly with my column rowversion in database.

Here is the problem.

1) I List items
2) I go update one item, (supose with id 4)
3) I send to the form in a hiddenfield the value of the rowversion
4) Someone updated in database some field in id 4 (making the rowversion to change)
5) I update the new values
6) i Convert string 开发者_运维技巧data with rowversion to byte[]
7) I get the object with primary key from the database and affect all properties of the object returned from database with model binded object that come from the form post including the rowversion!
8) I invoke SaveChanges()
9) The Problem!

I go to profiler and i see that the query that is build contains the Newer version and not the older (not that i affected from the post form to the object that come from the database).

For me appears that EF when is building is using the newVersion in some place, and not uses the current value that controls concurrency in the object..

Somebody know what it is happening????


The EF tracks two values for every property: The value originally read from the DB, and the new value you assign.

For the concurrency token / row version, it always uses the original value in the WHERE when doing the update. This does make sense if you think about it, but it doesn't work for your situation.

In your Step 7, you get the new value of the timestamp, created during the update in step 4. So that's what appears in the WHERE clause. Updating the property of the entity doesn't fix this, because that changes the "current" value of the property, not the "originally read" value.

Here's a workaround:

// get updated object from DB, with "newer" concurrency token/timestamp
var myFoo = myContext.Foos.Single(f => f.Id == id);
// assign the "current" value of ConcurrencyToken
myFoo.ConcurrencyToken = concurrencyToken; 
// now copy the "current" value you just assigned to the "originally read from DB" 
// value, overwriting the ConcurrencyToken value you read from DB
var ose = Context.ObjectStateManager.GetObjectStateEntry(myFoo);
ose.AcceptChanges(); 
// assign rest of properties
myFoo.SomeOtherProperty = someOtherValue;
Context.SaveChanges();


Here is my workaround.. for persistance ignorant:

       public void Update<TEntity>(TEntity Entity) where TEntity : class {
            ObjectStateEntry entry = _Context.ObjectStateManager.GetObjectStateEntry(Entity);
            entry.ChangeState(EntityState.Modified);
            entry.AcceptChanges();
            entry.ChangeState(EntityState.Modified);
        }

The essence is..

POCO don't notify the context for changes, so when i update an entity, the entry still remains unchanged.

1) I get the entry with Entity passed in the method
2) I change the state to Modified
3) I call AcceptChanges.. (note that in step 2 i changed the state to modified, so AcceptChanges now copies the CurrentValues to OriginalValues.. - Looks that implementation of AcceptChanges just procede if the state are different than Unchanged and makes sence)
4) I got the values copied but the default behavior of acceptChanges is let the state Unchanged..
5) I change the state to modified, so the SaveChanges can build the Update Command.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜