Search code examples
c#entity-frameworkobjectstatemanager

How to clear ObjectStateManager


I would like to clear the ObjectStateManager, so that after calling SaveChanges(); on the DbContext the following line returns no result:

dbContext.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Unchanged);

The behaviour seems to be that all objects (Added, Modified) in the ObjectStateManager gets the State changed to Unchanged, so the code will return them all. Is there a way to clear it?

I need this since I am reusing the context and do some stuff for the Entities with Unchanged state but since the ObjectSateManager grows and grows with Unchanged Entities (since it changes them all to Unchanged after SaveChanges) its doing the same work for one Entity over and over.

Edit:

Why the detach method isnt working for me:

Lets assume you have 2 classes:

public class Nation
{
    public string Name { get; set; }
    public ICollection<City> Cities { get; set; }
}

public class City
{
    public string Name { get; set; }
    public Nation Nation { get; set; }
}

Now I have passed to the SaveChanges a Nation Item with some Cities that need to be either updated or inserted.

Lets assume the following:

var canada = new Nation()
{
    Name = "Canada",
}

canada.Cities = new City[] 
    { 
        new City(){ Name = "Ottawa", Nation = canada, }, 
        new City(){ Name = "Edmonton", Nation = canada, }, 
        new City(){ Name = "Victoria", Nation = canada, }, 
        new City(){ Name = "Torronto", Nation = canada, } 
    },
}

Now I have all those objects in the Unchanged state inside my ObjectStateManager. (After the SaveChanges call)

I than loop through them and set the state to unchanged, this result in every City having Nation = null and Nation.Cities being empty.


Solution

  • I found a solution that works for me "perfectly", it doesnt Clear the ObjectStateManger but ignores all the previously attached/processed entities.

    private static int __lastProcessedIndex = 0;
    private static DbContext _oldContext = null;
    
    public void DoYourMagic(DbContext context)
    {
        if (ReferenceEquals(context, _oldContext) == false)
        {
            _oldContext = context;
            _lastProcessedIndex = 0;
        }
    
        var objectContext = (context as IObjectContextAdapter).ObjectContext;
        var unchanged = objectContext.ObjectStateManager.GetObjectSateEntires(EntityState.Unchanged).ToArray();
    
        for (int i = _lastProcessedIndex; i < unchanged.Length; i++)
        {
            //do your magic with unchanged entities...
        }
    
        context.SaveChanges();
    
        //Now all entries in objectstatemanager are in state Unchanged
        //I am setting the index to the Count() - 1
        //So that my next call of the method "DoYourMagic" starts the for with this index
        //This will than ignore all the previously attached ones
        _lastProcessedIndex = objectContext.ObjectStateManager.GetObjectSateEntires(EntityState.Unchanged).Count();
    }