Question

I am trying to handle a situation in a bulk insert process where there may be entities with the same primary key, which of course is going to make SaveChanges throw an exception.

Here's what I have:

try
{
    _context.SaveChanges();
    _context.Dispose();
    _context = null;
    _context = SelectContext<T>();
    _commitCount = 0;
}
catch (System.Data.UpdateException updateEx)
{
    //Remove from _context all the entries that errored in the SaveChange() process...
    if (updateEx.StateEntries != null)
    {
        foreach (ObjectStateEntry stateEntry in updateEx.StateEntries)
        {

            if ((System.Data.EntityState)stateEntry.Entity.GetType().GetProperty("EntityState").GetValue(stateEntry.Entity, null) != System.Data.EntityState.Detached)
            {
                _context.Detach(stateEntry.Entity);
            }
         }

}

//Save context changes again this time without erroneous entries...
try
{
     _context.SaveChanges();
     _context.Dispose();
     _context = null;
     _context = SelectContext<T>();
     _commitCount = 0;
 }
 catch (Exception ex)
 {                  
   //Welp, at the point, I'm clueless...
 }

If I look in the ObjectStateManager, the entity is indeed removed (the count goes down by the number of time the foreach loop is iterated.)

But it still throws an exception on the second attempt, whinning about a dupe PK.

I tought detaching an entity was the same is if it was never in the context in the first place. Do I need to do something else ?

Thanks.

Was it helpful?

Solution 2

This is what I ended up doing in my case:

_context.ObjectStateManager.ChangeObjectState(stateEntry.Entity, System.Data.EntityState.Unchanged);
_context.ApplyOriginalValues<T>(entityType, (T)stateEntry.Entity);
_context.Detach(stateEntry.Entity);

After that, I'm able to save the context changes.

OTHER TIPS

Deatch doesn't fully undo the changes. Per the msdn doc "Only the entity is removed; if there are any related objects that are being tracked by the same ObjectStateManager, those will not be detached automatically."

Only the entity you pass to detach is removed. Other changes will cause a failure. Will there be contention for you db? If this application is the only thing making changes to the db you can undo changes with context.Refresh(RefreshMode.StoreWins, object); otherwise, it's a bit more complicated.

You have to do something like this;

 var entry = context.ObjectStateManager.GetObjectStateEntry(((IEntityWithKey)object).EntityKey);

  for (int i = 0; i < entry.OriginalValues.FieldCount; i++)

{

     entry.CurrentValues.SetValue(i, entry.OriginalValues[i]);

}

entry.AcceptChanges();

The above code uses the ObjectSateManager to return all modified objects to their original states, after that context.SaveChanges(); shoudl succeed.

You may also find this useful http://dotnetadventurer.blogspot.com/2010/09/discarding-changes-to-objectcontext-in.html I haven't tried his code and I usually initialize my context differently so I'm not sure if it will work with your example but it's very simple so if it does, it's the route I would go.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top