Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework: Can I Include() properties of subtypes?

I have a TPT inheritance set up in my EF project with one supertype and two subtypes. I want to get all objects of the supertype and Include() the navigation properties of the subtypes, to this effect (class names changed to protect the befuddled):

var thelist = DataContext.Fleets
    .Include(x => x.Vehicles.Select(y => y.EngineData)) // Not specific to Car or Truck
    .Include(x => x.Vehicles.OfType<Car>().Select(y => y.BultinEntertainmentSystemData)) // Only Cars have BultinEntertainmentSystemData
    .ToList();

So, I want to get all vehicles, including the info on the built-in entertainment system if the vehicle is a car. I've seen that this is doable if I'm going straight from the DbSet, but here I'm looking at a collection property of a Fleet object. When I use an Include() call with an OfType() call on the collection property, I get this Exception message in reply:

The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.

Is it possible to Include() properties of subtypes within a collection property?

like image 804
Peter Bailey Avatar asked Dec 12 '16 16:12

Peter Bailey


1 Answers

You can't do what you are trying because the queries you are writing are "translated" to SQL. There are no "OfType" method in SQL and OfType is not set as a property on your object, so you get this error. Ideally EF would translate this to mean only get data from the table that contains the Type Car, but it does not.

If you add a property on the parent that indicates the type, you can use that one to navigate though.

public class Vehicle
{
    public string Type {get; set;} //you need the setter here for EF
}

public class Car : Vehicle
{
    public Car()
    {
        Type = "Car";
    }
}

DataContext.Fleets
    .Include(x => x.Vehicles.Select(y => y.EngineData)) // Not specific to Car or Truck
    .Include(x => x.Vehicles.Where(x => x.Type == "Car").Select(y => y.BultinEntertainmentSystemData)) // Only Cars have BultinEntertainmentSystemData
    .ToList();

This is just something I came up with now, you might have to refine it. Using strings to define something like this might not be ideal, try making it an enum and so on.

like image 89
ruffen Avatar answered Nov 03 '22 12:11

ruffen