192

There is no Detach(object entity) on the DbContext.

Do I have the ability to detach objects on EF code first?

Scott Stafford
  • 43,764
  • 28
  • 129
  • 177
Shawn Mclean
  • 56,733
  • 95
  • 279
  • 406

3 Answers3

327

This is an option:

dbContext.Entry(entity).State = EntityState.Detached;
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • 3
    Can I do this when retrieving objects that returns an IQueryable? – Shawn Mclean Apr 08 '11 at 19:06
  • 1
    @Lol coder: I am not sure if I understand you right, but `entity` must be a materialized object of a type which is part of your model classes (Person, Customer, Order, etc.). You cannot directly pass in an IQueryable into `dbContext.Entry(...)`. Is that the question you meant? – Slauma Apr 08 '11 at 19:37
  • what is the solution? `AsNoTracking()` or `Include()` or `dbContext.Entry(entity).State = EntityState.Detached;` – Elad Benda Feb 06 '13 at 11:14
  • 13
    @EladBenda: It depends. If you want to detach an object that is already attached to the context, set the state to `Detached`. If you want to load entities from the DB without attaching them at all to the context (no change tracking), use `AsNoTracking`. – Slauma Feb 06 '13 at 12:47
  • 1
    I found an interesting problem with this method. Even though the entity may be a proxy class, lazy loading will not work after you change its state to `Detached`. – kjbartel Aug 20 '14 at 23:44
  • 4
    @kjbartel : this is the expected behavior, since the entity has no link with the context. – Ricardo Souza Jun 18 '15 at 14:54
  • 2
    @rcdmk If you get an entity with `AsNoTracking` like in the other answer then lazy loading will still work. This method will not. – kjbartel Jun 19 '15 at 12:27
  • 1
    don't forgot `SaveChange `and `EntityState.Modified` before `EntityState.Detached` – Hamed Oct 14 '20 at 09:28
187

If you want to detach existing object follow @Slauma's advice. If you want to load objects without tracking changes use:

var data = context.MyEntities.AsNoTracking().Where(...).ToList();

As mentioned in comment this will not completely detach entities. They are still attached and lazy loading works but entities are not tracked. This should be used for example if you want to load entity only to read data and you don't plan to modify them.

saluce
  • 13,035
  • 3
  • 50
  • 67
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 3
    @Ladislav: This is indeed probably what Lol coder meant. I've never used and thought about this method although I often load object lists and dispose the context at once, something like `using(ctx){ return ctx....ToList(); }`. In such cases using `AsNoTracking()` would make much sense because I'd save filling up the object context unnecessarily. I guess it would probably have a performance and memory consumption benefit especially for large lists, right? – Slauma Apr 08 '11 at 20:23
  • 1
    @Slauma: Yes it has performance benefit. That is actually why this method exists. Using this approach in ObjectContext API is little bit more complicated. – Ladislav Mrnka Apr 08 '11 at 21:15
  • 2
    Does this disable lazy loading? – Shawn Mclean Apr 16 '11 at 03:27
  • 3
    Actually this will not disable lazy loading it will only disable change tracking and improve performance = entity is still attached. I found it after answering this question so you should mark @Slauma's one as a valid answer. – Ladislav Mrnka Apr 16 '11 at 20:36
  • 1
    This is what I want. I want lazy loading and the ability to only modify a detached entity. – Shawn Mclean Apr 17 '11 at 04:16
  • 1
    @Ladislav: To your comment above from Apr 16: Did you test this with a model with lazy loading enabled? I have just used `AsNoTracking` in a model without lazy loading and the entities are *not* attached to the context. Perhaps it is so: 1) Change tracking is always disabled (no snapshot is taken). 2) If lazy loading is disabled the entity is loaded in detached state, otherwise the entity is attached (necessary for lazy loading). – Slauma Apr 29 '11 at 20:23
  • what is the solution? `AsNoTracking()` or `Include()` or `dbContext.Entry(entity).State = EntityState.Detached;` – Elad Benda Feb 06 '13 at 11:20
  • AsNoTrcking() is not work for me. I used "entity.Configuration.ProxyCreationEnabled = false". – wearetherock Nov 13 '13 at 15:29
  • Entities loaded via `AsNoTracking()` are yielded in `Detached` state. – Peter Ivan Feb 13 '17 at 11:00
  • This is not detaching objects, this is NOT attaching them. – AgentFire Jul 25 '23 at 11:33
12

Both previous answers provide good instructions, however, both might leave you with the entities still loaded into EF's context and/or its Change Tracker.

This is not a problem when you are changing small data sets, but it will become an issue when changing large ones. EF would have increased memory and resource usage, which in turn would reduce the procedure performance as it uses more data/entities.

Both other approaches are valid but, In this case, Microsoft recommends cleaning the Change tracker instead of detaching the entities individually

Clearing the Change tracker on the data changing loop (which changes a chunk of data for instance) can save you from this trouble.

context.ChangeTracker.Clear();

This would unload/detach all entities and its related changeTracker references from the context, so use with care after your context.SaveChanges().

The Fabio
  • 5,369
  • 1
  • 25
  • 55
  • *both would leave you with the entity still loaded into EF's Change Tracker* -- That's not true. Detaching an object removes it from the change tracker. If the entity is a lazy-loading proxy then it has a reference to the context, but that's not the same as being attached to it (Ladislav's phrasing is a bit ambiguous here). – Gert Arnold Dec 14 '21 at 12:32
  • Hi Gert, You can verify it with a quick test. The entity remains in the ChangeTracker with a state of detached. Similar to a memory leak (but unfortunately by design..). Calling the Clear command removes all of the instantiated entity objects from the Context – The Fabio Dec 15 '21 at 05:07
  • Of course the state is detached, what else? Even if you create a brand new entity that has never even seen a context its state is detached. It's just EF's way of saying: don't know this one, nothing to do with it. The alternative would be to throw an exception when verifying the state of any entity outside the context. Of course nobody wants that. – Gert Arnold Dec 15 '21 at 19:22
  • 1
    and yet EF retains it in memory detached like a memory leak – The Fabio Dec 16 '21 at 04:30
  • Then please show how. Your statement doesn't have any backing. – Gert Arnold Dec 16 '21 at 07:45
  • *Only lazy-loading proxies*. And the context doesn't have reference to *them* when they're detached. It's not that EF keeps them in memory. It's the application that *may* keep proxies alive for a long time, which may cause a memory leak because the context they refer to can't be GC-ed. That's not EF's fault. Your statements are clearly rooted in the misconception that when EF reports an object as detached, it has to have it in its change tracker somehow. It hasn't. – Gert Arnold Dec 17 '21 at 07:55
  • You are getting there, still have a little to learn from the usage of EF though. Good luck on your efforts – The Fabio Dec 19 '21 at 21:44
  • 2
    Thanks @TheFabio - this solved a massive performance issue when bulk inserting very large graphs in EF. To solve it, I used your line after saving each entity, and the performance increase and memory usage improvement was awesome. Thanks! – dalcam Dec 31 '21 at 03:58