Entity Framework Update Existing Object

921 Views Asked by At

I have added a row to my database and come back with a different context to update it. I have this class:

public abstract partial class DataManager<I, C> 
    where C : class, IDomainObject, I, new( ) where I : IDomainObject

C might be an EntityObject, but this class doesn't know that.

My Save looks like this:

    public virtual bool Save( I _item )
    {
        bool rc = true;
        try
        {
        var set = m_Context.GetObjectSet<I, C>( );
        ObjectStateEntry stateEntry = null;
        if( ! m_Context.ObjectStateManager.TryGetObjectStateEntry( ( C ) _item, out stateEntry ) )
        {
            if( _item is EntityObject )
            {
                    if ( _item.IsNew )
                    {
                        set.AddObject( ( C ) _item );
                    }
                    else
                    {
                        try
                        {
                            set.Attach( ( C ) _item );
                        }
                        catch( Exception ex )
                        {
                            set.ApplyCurrentValues( ( C ) _item );
                        }

and so on...

In my test case, stateEntry is not found by TryGetObjectStateEntry. It is, however, an EntityObject, and it is not new (IsNew is my flag), so it gets to the else. Here's my problem: set.Attach throws this error

"An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."

and in the very next instant, ApplyCurrentValues throws this one:

"An object with a key that matches the key of the supplied object could not be found in the ObjectStateManager. Verify that the key values of the supplied object match the key values of the object to which changes must be applied."

How can these both be true?

MORE INFORMATION:

_item was created by a Get in another context. That context was then disposed. At that point, _item had an EntityState.Unchanged. I applied some changes to it, and it changed to EntityState.Modified. (I didn't expect that, since the context (and its ObjectStateManager) should have been gone.) At any rate, once it gets to Save (above), it's state (as reported by the debugger) is Modified, but I have a new context by then. If I get a list of ALL the ObjectStateEntries (Added, Deleted, Modified, Unchanged) at this point, there are only two, and _item is not one of them, as ApplyCurrentValues reports, but it can't be Attached because "it is too there!". Perhaps the problem is that it is still attached to an old ObjectStateManager (could there some reference which won't let the ObjectStateManager dispose?).

2

There are 2 best solutions below

2
Boomer On

The problem is that each time the db-context is initialized, it takes the rows from the database and foreach row, assign an entity key. which means the same row, retrieved by 2 db-context will have 2 different entity keys. the entity key is like an id in entity framework and it is used instead of the ID of the entity in question. But the constraints of the tables are although preserved (no duplicate primary key) Hope this make sense.

0
Danny Varod On

The problem is that you are attaching two different users with the same org, however, the org object is a different instance in each case.

If the organization is already in the DB, try:

  1. Either setting the navigation properties to the organization to null and only set the OrganizationId properties.

  2. Or load the organization entity from the DB and put it the nav props.

If the organization is not in the DB:

Use the same instance (throw one away and replace it with the other).