Search code examples
c#entity-frameworktph

Using EF Include on TPH


I have implemented code first db architecture with simple inheritance using THP: Database diagram

And I need to query all notifications of all type. TargetUser property in NotificationUser table is a association. I'm trying to execute next code:

var notifications = _context.Notifications;
foreach (var notification in notifications)
{
    Debug.WriteLine((notification is NotificationUser)? ((NotificationUser) notification).TargetUser?.Name : "-");
}

In database propety TargetUser is set to correct foreign key, but in code I don't get any result. Lazy loading is enabled.

Is it possible to user eager loading? I had already tried to write _context.Notifications.Include('TargetUser') byt it throws an exception.


Upd. The exception is:

A specified Include path is not valid. The EntityType 'Core.Concrete.NotificationBase' does not declare a navigation property with the name 'TargetUser'.

Tried to modify this answer to:

var notifications = _context.Notifications.OfType<NotificationUser>()
                .Include(n => n.TargetUser)
                .Cast<NotificationBase>()
                .Union(_context.Notifications.OfType<NotificationPlace>()

but still the same exception is thrown.


Solution

  • Already tried a lot of different solutions, and none fit my requirements, as I'm working on an API, and the query must support pagination and make constant requests to the database (and not loading all entities in memory).

    Finally found out a solution, perhaps not the best, but enough for now. Firstly, I request a portion of ordered data (pagination logic):

    var notifications = _context.Notifications
                .OrderByDescending(n => n.DateTime)
                .Skip(offset)
                .Take(limit);
    

    (At this point I'm not interested in any properties) Next, I'm getting the Id's of loaded items for each entity type:

    var ids = notifications.OfType<NotificationUser>().Select(n => n.Id).ToList();
    

    and lastly load specific entities including all properties:

    var userNotifications = _context.Notifications.OfType<NotificationUser>()
                 .Include(n => n.TargetUser)
                 .Include(n => n.TargetUser.Images)
                 .Where(n => ids.Contains(n.Id))
                 .ToList();
    

    all entities goes to list and sorted one more time.

    A lot of bad stuff here, hope someone can provide better solution.