Frage

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.

War es hilfreich?

Lösung 3

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();
}

Andere Tipps

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(...);

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top