24

Given the following model ...

public class Parent
{
    public int Id { get; set; }
    public ICollection<Child> Children { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public ICollection<Grandchild> Grandchildren { get; set; }
}

public class Grandchild
{
    public int Id { get; set; }
}

... we can eager load with Include a Parent with all Children and Grandchildren in one step like so:

context.Parents.Include(p => p.Children.Select(c => c.Grandchildren))

Is something similar possible for explicit loading?

The child collection can be explicitely loaded this way:

Parent parent = context.Parents.Find(parentId);
context.Entry(parent).Collection(p => p.Children).Load();

But trying to load the children in a similar way as with Include ...

context.Entry(parent)
    .Collection(p => p.Children.Select(c => c.Grandchildren)).Load();

... doesn't compile und the string overload of Collection ...

context.Entry(parent).Collection("Children.Grandchildren").Load();

... throws an exception ("...no dotted paths allowed...").

The only thing which I found working is to explicitely load the Grandchildren in a loop:

Parent parent = context.Parents.Find(parentId);
context.Entry(parent).Collection(p => p.Children).Load();
foreach (var child in parent.Children)
    context.Entry(child).Collection(c => c.GrandChildren).Load();

I am wondering if I missed something and if there is some other way to explicitely load the GrandChildren in one roundtrip.

Thanks for feedback in advance!

Slauma
  • 175,098
  • 59
  • 401
  • 420
  • Did you try `Collection(...).Query().Include(...).Load()`? If it doesn't work as well I'm afraid that it is not supported. Generally `Load` is equivalent of handling `RelatedEnd.Load` from ObjectContext API. – Ladislav Mrnka May 11 '11 at 15:50
  • @Ladislav: Please put this in an answer :) It works! – Slauma May 11 '11 at 15:58

1 Answers1

24

As I pointed in the comment you can try to get query for relation first, then add includes and execute loading. Something like:

context.Entry(parent)
       .Collection(p => p.Children)
       .Query()
       .Include(c => c.Grandchildren) // I'm not sure if you can include grandchild directly  
       .Load();
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Yes, that's exactly what I tried after your comment, and it works. It opens the question, if you could then also load "GrandGrandChildren" with `Include(...Select(...))` and so on. But I'd guess it will work too. Thanks for this solution! – Slauma May 11 '11 at 16:12
  • I've just tested the code with your `IncludeMultiple` (instead of simple Include) from here (http://stackoverflow.com/questions/5376421/ef-including-other-entities-generic-repository-pattern/5376637#5376637) with "GrandGrandChildren" and "SomeReferenceInGrandChild" and it works too! – Slauma May 11 '11 at 16:34
  • It should work because `Query()` returns `ObjectQuery` implementing `IQueryable` so it is EF query as any other only with some predefined condition. – Ladislav Mrnka May 11 '11 at 19:23
  • Late to this thread, I know, but the `Load()` only covers entities specified _after_ the `Query()` (Grandchildren). But then a second SQL call is made to load the missing entity layer (Children). So you get 2 SQL calls, but everything ends up loaded. To be fully explicit, use two calls, the first being: `context.Entry(parent).Collection(p => p.Children).Load();` – Neil Laslett Aug 15 '13 at 19:08
  • I am super late to this party, but this still works in EF6 – Brian P Nov 24 '16 at 14:02