FrankE
FrankE

Reputation: 313

EntityFramework: EntityCollection.Remove has severe performance issue

I'm having a severe performance problem with removing an object from an collection object via a navigation property. When EntityCollection.Remove is called it takes 8 minutes (!!!!) to finish

Details: CollectionObject X has 65.000 Objects. Only one of them should be removed from the collection.

There is not much own code involved, i.e. the EntityCollection is created via (generated code)

RelationshipManager.GetRelatedCollection<...>(<relationShipName>, <targetRoleName>)

and the actual Remove is simply a call of

EntityCollection<Type>.Remove

I suspect that the EntityFramework loads all 65.000 objects before doing the actual remove. So far however I haven't been able to prove this assumption.

Any ideas?

Thanks Frank

Additional information: I found this useful link: EF builds EntityCollection, but I (think I) want IQueryable The real cause of the problem is the behavior of EntityCollection when doing a Remove.

I found a kind of workaround and use the smaller side of the relation, i.e. when I want to remove a relation from object A to object B, when object A has 65000 objects, I remove the relation from the object B side, where the performance is okay, because object B is related only to e.g. 10 objects. Obviously this is not a satisfactory and general solution for the problem.

Upvotes: 2

Views: 347

Answers (1)

Matthew Fotzler
Matthew Fotzler

Reputation: 640

Yes, it probably is loading all the objects before doing the remove. You can use the SQL Profiler tool that comes with SQL Server to verify this.

As far as removing the object goes, if you need to get at this navigation property, you can use CreateSourceQuery on the EntityReference. if your navigation property is called Candles, then the EntityReference will be called by default CandlesReference. So your deletion looks like this:

var victim = entity.CandlesReference.CreateSourceQuery().Single(c => .....);
context.DeleteObject(victim);
context.SaveChanges();

This will get the query that would have been executed, and give you a chance to just pick off the one you want, without having to grab everything first.

Assuming you have the necessary info, it may be more efficient to directly query, like

var victim = context.Candles.Single(c => ....);

Upvotes: 1

Related Questions