Dr. Strangelove
Dr. Strangelove

Reputation: 3328

EF Core nested ThenInclude

I am using EntityFramework (EF) Core and ASP.NET core.

My model is as:

class Zoo
{
    public ICollection<Animal> Animals {set; get;}
}

class Animal
{
    public ICollection<Dog> Dogs {set; get;}
}

class Dog
{
    public ICollection<Shepherd> Shepherds {set; get;}
}

(This is not exactly how my model is defined, the example is close enough, hope it can simply show the nested relation.)


Question

I would like to query a Zoo with a given id, and include Animals, Dogs, and Shepherds in the result. I have:

var animals = await context.Zoo
                    .Include(zoo => zoo.Animals)
                    .ThenInclude(animal => animal.Dogs) // operates on the Animal type
                    .FirstAsync(zoo => zoo.ID = id)

Any thoughts on how I can add Shepherds?

(Note: I am aware of this discussion on Github, though not sure how to leverage the suggested method to go deeper in my nested relational-model.)

Upvotes: 0

Views: 3020

Answers (1)

poke
poke

Reputation: 387677

If you want to include the dog.Sheperds in the result, then just continue with the ThenInclude calls:

var animals = await context.Zoo
    .Include(zoo => zoo.Animals)
        .ThenInclude(animal => animal.Dogs)
            .ThenInclude(dog => dog.Sheperds)
    .FirstAsync(zoo => zoo.ID = id);

Each of the ThenInclude() calls operates on the previous result, so you can use this to go deeper. It’s only Include() that resets back to the original level. So if you wanted to include multiple collections from Animal for example, then you would have to start at the beginning again for those:

var animals = await context.Zoo
    .Include(zoo => zoo.Animals)
        .ThenInclude(animal => animal.Dogs)
            .ThenInclude(dog => dog.Sheperds)
    .Include(zoo => zoo.Animals)
        .ThenInclude(animal => animal.Cats)
    .FirstAsync(zoo => zoo.ID = id);

Note: When using ThenInclude, IntelliSense will often give you the autocomplete hints for the first overload that operates on TPreviousProperty instead of IEnumerable<TPreviousProperty>. If you just continue and use the correct overload, it will eventually figure it out though and it will not stop you from compiling it properly.

Upvotes: 7

Related Questions