176

I am using Entity Framework 5 code first and ASP.NET MVC 3.

I am struggling to get a child object's child object to populate. Below are my classes..

Application class;

public class Application
{
     // Partial list of properties

     public virtual ICollection<Child> Children { get; set; }
}

Child class:

public class Child
{
     // Partial list of properties

     public int ChildRelationshipTypeId { get; set; }

     public virtual ChildRelationshipType ChildRelationshipType { get; set; }
}

ChildRelationshipType class:

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

     public string Name { get; set; }
}

Part of GetAll method in the repository to return all the applications:

return DatabaseContext.Applications
     .Include("Children");

The Child class contains a reference to the ChildRelationshipType class. To work with an application's children I would have something like this:

foreach (Child child in application.Children)
{
     string childName = child.ChildRelationshipType.Name;
}

I get an error here that the object context is already closed.

How do I specify that each child object must include the ChildRelationshipType object like what I did above?

jdmcnair
  • 1,305
  • 15
  • 33
Brendan Vogt
  • 25,678
  • 37
  • 146
  • 234
  • Possible duplicate of [Entity Framework - Include Multiple Levels of Properties](https://stackoverflow.com/questions/10822656/entity-framework-include-multiple-levels-of-properties) – Michael Freidgeim Sep 04 '18 at 14:16

4 Answers4

290

If you include the library System.Data.Entity you can use an overload of the Include() method which takes a lambda expression instead of a string. You can then Select() over children with Linq expressions rather than string paths.

return DatabaseContext.Applications
     .Include(a => a.Children.Select(c => c.ChildRelationshipType));
Ryan Amies
  • 4,902
  • 1
  • 21
  • 36
  • 6
    As GraemeMiller said, strongly typed classes are better for maintainability than using strings – Ryan Amies Oct 24 '12 at 14:08
  • Which version did the lamba method come available? I'm stuck on a EF 4.0 Codebase..and cant' get the lamdas to work. Thanks for any input. – granadaCoder Sep 02 '14 at 19:39
  • 5
    It will work in EF 4, just make sure to add a reference to `System.Data.Entity;` – Ryan Amies Sep 05 '14 at 11:08
  • 5
    FYI - In EF 6 the namespace is `Microsoft.Data.Entity` – Brad Aug 07 '15 at 22:45
  • 1
    Using EF 5, I could not get .Select(x => x.Child) but this worked - Entities.UserProfile storedProfile = db.UserProfiles .Include(s => s.ShippingAddress) .Include(st => st.ShippingAddress.StateProvince) .Include(b => b.BillingAddress) .Include(bs => bs.BillingAddress.StateProvince) .FirstOrDefault(x => x.UserId == userId); – Geovani Martinez Dec 28 '18 at 00:45
  • Thank you for mentioning the correct library to use, all too often people omit this important nugget of information. – Mike Jan 20 '21 at 01:29
165

With EF Core in .NET Core you can use the keyword ThenInclude :

return DatabaseContext.Applications
 .Include(a => a.Children).ThenInclude(c => c.ChildRelationshipType);

Include childs from childrens collection :

return DatabaseContext.Applications
 .Include(a => a.Childrens).ThenInclude(cs => cs.ChildRelationshipType1)
 .Include(a => a.Childrens).ThenInclude(cs => cs.ChildRelationshipType2);
Hayha
  • 2,144
  • 1
  • 15
  • 27
25

I ended up doing the following and it works:

return DatabaseContext.Applications
     .Include("Children.ChildRelationshipType");
mattruma
  • 16,589
  • 32
  • 107
  • 171
Brendan Vogt
  • 25,678
  • 37
  • 146
  • 234
  • 93
    The strongly typed way is better. Magic strings aren't good for refactoring – GraemeMiller Oct 24 '12 at 13:20
  • @GraemeMiller , you re right, it is a lot better when debugging, refactoring or changing the code in any way, but (sadly) "strongly typed" just does not work - for me. So I'm stuck with magic stings. – Tamas Feb 07 '23 at 13:54
  • I will go with a solution using `nameof` expressions: `string.join('.', nameof(Children), nameof(Children.ChildRelationshipType))` - at least I will be able to "FindAllReferences" – Tamas Feb 07 '23 at 14:14
3

A good example of using the Generic Repository pattern and implementing a generic solution for this might look something like this.

public IList<TEntity> Get<TParamater>(IList<Expression<Func<TEntity, TParamater>>> includeProperties)

{

    foreach (var include in includeProperties)
     {

        query = query.Include(include);
     }

        return query.ToList();
}
gcoleman0828
  • 1,541
  • 3
  • 30
  • 49