0

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.

Rand Random
  • 6,067
  • 9
  • 36
  • 77
  • 2
    You should keep your context open for as little time as possible. Sharing/reusing context within the entire application is a bad idea. – MarcinJuraszek Feb 11 '14 at 19:30
  • @MarcinJuraszek I am doing a Import method which calls the SaveChanges for each element, since I want to get immediate feedback on each result, since the whole Import has in total 10.000 entities to save I believe that using one context, and one transaction is better than trying to create 10.000 contexts with 1? transcation for a complete rollback. – Rand Random Feb 11 '14 at 19:39
  • What do you need the entities that are detached for? Isn't it like you finished working with them once they are saved? – Ivo Feb 12 '14 at 14:45
  • @ivowiblo Sadly I still need them. :( Its part of the requirement of the app that my boss gave me, thats forcing me to do stuff thats not really entity framework "friendly", but I already found a solution that works for me, see my answer. – Rand Random Feb 12 '14 at 15:18

3 Answers3

0

The Detach method of the ObjectContext will remove it from the object context:

dbContext.ObjectContext.Detach( entity );

Also, if you don't need to have the entities attached, you can use the AsNoTracking() extension method. It will execute the query without tracking:

var items = dbContext.Items.AsNoTracking().Where(...);
Ivo
  • 7,825
  • 4
  • 25
  • 41
0

What you can do is to use paging. Create a new fresh DbContext every N objects, but all of them using the same connection and transaction.

Ivo
  • 7,825
  • 4
  • 25
  • 41
0

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();
}
Rand Random
  • 6,067
  • 9
  • 36
  • 77
  • The problem with this is that it doesn't scale at all. Are you actually loading 10k objects from the db without disposing them? Is it possible that that number grows? – Ivo Feb 12 '14 at 15:38
  • Yes I am loading those and no the number isnt growing, thats the maximum its very very very rare to have anything this large at all - more likely would be something around 3.000. – Rand Random Feb 12 '14 at 15:43
  • @ivowiblo forgot the (a)xxxx, see my previous comment. sry. – Rand Random Feb 12 '14 at 16:28