X

Include for derived types in Entity Framework 2.1

When I wrote user interface for my TemperatureStation solution I faced some bad problems with Entity Framework Core when trying to query base type and get some navigation properties of derived types included. I was able to come out with some work-arounds that were far from being satisfying for me. Include for derived types in Entity Framework Core solves the problem.

Problem

Suppose we have some Entity Framework Core model classes representing readings taken from sensors. There are also readings calculated by special calculator classes. This is simplified fragment of code from my TemperatureStation solution available in GitHub. In some views I need to load readings and include calculators and sensors to display their names with readings. Take a look at the following code.

public abstract class Reading
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public DateTime ReadingTime { get; set; }

    public string ReadingType { get; set; }

    [NotMapped]
    public abstract string Name { get; }

    public double Value { get; set; }
}

public class Calculator
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }
    public string Parameters { get; set; }
}

public class CalculatorReading : Reading
{
    [Required]
    public Calculator Calculator { get; set; }

    public override string Name
    {
        get { return Calculator?.Name; }
    }
}

public class Sensor
{
    [Key]
    public string Id { get; set; }

    [Required]
    public string Name { get; set; }
}

public class SensorReading : Reading
{
    [Required]
    public Sensor Sensor { get; set; }

    public override string Name
    {
        get { return Sensor?.Name; }
    }
}

The problem is that we don’t have good way to load Sensor and Calculator with readings of their type. Okay, it’s possible to load all sensors and calculators to memory before querying and having change tracking turned on event for read-only cases but it is hack that works only in specific situations.

Including properties of derived types

Entity Framework 2.1 solves the issue by introducing include for derived types. We can cast base type to derived type when calling Include() method and tell what navigation property we want to be included like shown next.

var readings = _context.Readings
                        .Include(reading => (reading as SensorReading).Sensor)
                        .Include(reading => (reading as CalculatorReading).Calculator)
                        .OrderByDescending(reading => reading.ReadingTime)
                        .Take(10)
                        .ToList();

This is completely valid query in Entity Framework Core 2.1 and it helps to avoid all kind of nasty hacks we needed with limitations we had before.

Wrapping up

Entity Framework 2.1 is big step forward and I am glad to see that painful problems get solved version by version. Include for derived types was one of those problems that wasn’t easy to solve before. It needed work-arounds and sometimes pretty nasty hacks to make things work like expected. Include for derived types is elegant and nice solution to those problems.

Liked this post? Empower your friends by sharing it!

View Comments (5)

  • The font here is what Visual Studio is giving me when selecting Copy as HTML. It's Consolas.

    Anyway thanks for suggestion. I will try some fixed fonts and maybe I will find something that fits with blog design.

  • No success on implementing this on efcore 3.1.
    i was hoping that u could help.

    Currently my code look like :

    context.Sales.Include(x => x.SaleDetails)
    .ThenInclude(x => (x as ProductSaleDetail).Product)
    .Include(x => x.SaleDetails)
    .ThenInclude(x => (x as ProductSaleDetail).Unit)
    .Include(x => x.SaleDetails)
    .ThenInclude(x => (x as ServiceSaleDetail).Service);

  • Hi, do you know how can I resolve the same problem using Entity Framework 6? It would be great!
    Thanks

Related Post