32

I've just started using Entity Framework rather than my normal NHiberante to see how EF works and so far I'm having lots of problems but one in particular is detaching an object and keeping the related child objects.
I bought the O'Reilly Entity Framework book which tells you "yes entity framework by default doesn't keep the object graph when you detach" but it doesn't show how you how to keep the graph! Thanks O'Reilly thats really useful.

Anyway if anyone can help that would be great, code below:

        using (var creativeWorkshopEntities = new CreativeWorkshopEntities())
        {
            var q = from c in creativeWorkshopEntities.Job.Include("Files")
                    where c.Id == jobId
                    select c;

            var job = q.First();

            creativeWorkshopEntities.Detach(job);

            return job;
        }

Thanks!

Dan

4 Answers4

24

Try using a NoTracking query instead. That way the objects arenever attached, so you don't need to 'detach' which is when the graph is shredded:

i.e.

using (var creativeWorkshopEntities = new CreativeWorkshopEntities())        
{            
    creativeWorkshopEntities.Job.MergeOption = MergeOption.NoTracking;
    var q = from c in creativeWorkshopEntities.Job.Include("Files")
            where c.Id == jobId                    
            select c;            
    var job = q.First();            
    return job;
} 

Hope this helps

Alex

(Program Manager Entity Framework Team)

Alex James
  • 20,874
  • 3
  • 50
  • 49
  • That's great thanks Alex MergeOption done the trick for but the problem is without a detach my update method doesn't work, anyway around this? using (var creativeWorkshopEntities = new CreativeWorkshopEntities()) { if (job.Id > 0) creativeWorkshopEntities.AttachUpdated(job); //Custom extensor method else creativeWorkshopEntities.AddToJob(job); creativeWorkshopEntities.SaveChanges(); } –  Jul 22 '09 at 07:34
  • You need to use ApplyPropertyChanges(...) passing in the updated entity. ApplyPropertyChanges(updated) copies values from the 'updated' entity onto the original entity. For this to work the 'original' entity must be in the context, either because you held onto a copy and attached it (recommended) or because you did a query to re-load it from the database. – Alex James Jul 23 '09 at 21:40
  • 7
    Is there any way to prevent the entity graph from being shredded? Why is detaching implementing this way? – Den Nov 02 '10 at 13:59
  • 2
    what if I need to keep context alive?, I'm using 1 context per http request and even if I set MergeOption.NoTracking the entity stays connected – Juan Jimenez Sep 22 '11 at 19:18
3

In EF5 the MergeOption is not at the DbSet level anymore. So according to this: http://msdn.microsoft.com/en-us/data/hh949853.aspx

If you want to do a not tracking query you will need to do something like:

  var q = from c in creativeWorkshopEntities.Job.AsNoTracking().Include("Files")
                        where c.Id == jobId
                        select c;
Laggel
  • 1,356
  • 3
  • 19
  • 36
2

Check out http://www.codeproject.com/KB/architecture/attachobjectgraph.aspx

This is an awesome solution and may help you out - be aware that the author has an updated version on his own blog too - http://www.codetuning.net/blog/post/Entity-Framework-reattaching-entity-graphs-(3).aspx

Paul

Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158
0

use below code to keep related objects in memory.

  using (var creativeWorkshopEntities = new CreativeWorkshopEntities())
  {
                var q = from c in creativeWorkshopEntities.Job.Include("Files")
                        where c.Id == jobId
                        select c;

                var job = q.First();

                return (Job)Detach(job);
   }

  private Object Detach(Object object)
  {
            using (var stream = new MemoryStream())
             {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, dbo);
                stream.Position = 0;
               return formatter.Deserialize(stream);
             }
   }
Venkat
  • 868
  • 1
  • 12
  • 21
  • 2
    This only detaches a single object - not the entire graph. – Danny Varod Jul 19 '12 at 11:49
  • @DannyVarod Why would you think that? I've just tried this and it works as expected, all of the entities are there. – veljkoz Sep 17 '13 at 07:03
  • @veljkoz The built in detach from EF4 only detached a single object, this implementation clones the object. I can't remember why I wrote that - it was over a year ago and I can't see any edits. – Danny Varod Sep 17 '13 at 09:04
  • This doesn't actually detach anything. It simply clones the graph. The original graph is still in the context's local cache. If reducing memory footprint is part of your reasoning for wanting to detach your entity graph, then this doesn't help at all -- in fact it makes it worse. You also have to mark everything `[Serializable]` which is another detractor. – sliderhouserules Nov 04 '15 at 22:09
  • 2
    -1 Whilst this is recommended on MSDN forums ( https://social.msdn.microsoft.com/Forums/en-US/4ac62793-0c02-49b4-908c-c9cff9c53b38/detaching-complete-graph?forum=adodotnetentityframework ), as @sliderhouserules points out, this doesn't detach anything, it clones *everything* (the entire context, reachable via the object tracker reference). This can lead to *extreme* performance issues if there are lots (10k's) of objects in context (the bug I've just been chasing down all week). I strongly recommend avoiding this approach. – piers7 Nov 10 '15 at 08:12