Entity Framework Core to include different properties from subclasses

asp.net c# entity-framework-core

Question

The structure of my classes and repository:

public class Group{
    //fields
}

public class User{
    public UserRole Role {get;set;}
}

public abstract class UserRole{
    //fields
}

public class PersonUserRole:UserRole{
    public Group Group {get;set;}
}

public class ManagerUserRole:UserRole{
    public IList<Group> Groups {get;set;}
}

An example where I encounter the issue:

public class UserRepository:IUserRepository{
    private readonly ApplicationDbContext _dbContext;
    private readonly DbSet<User> _users;

    public UserRepository(ApplicationDbContext dbcontext)
    {
        _dbContext = dbcontext;
        _users = _dbContext.DomainUsers;
    }

    public User GetBy(int id)
        {
            User type = _users.Include(u => u.Role)
                              .SingleOrDefault(c => c.UserId == id);
            if (typeof(PersonUserRole) == type.Role.GetType())
            {
                return
                    _users.Include(u => u.Role)
                        .ThenInclude(r => (r as PersonUserRole).Groep)
                        .SingleOrDefault(c => c.UserId == id);
            }
            else
            {
                return _users.Include(u => u.Role)
                             .ThenInclude(r => (r as ManagerUserRole).Groups)
                             .SingleOrDefault(c => c.UserId == id);
            }
        }
}

I get the following error message:

Message "The property expression 'r => (r As PersonUserRole).Group' is not valid. The expression should represent a property access: 't => t.MyProperty'

It seems like I cannot cast my UserRole Type to the actual PersonUserRole Type to include the Group/Groups property. How can I include the properties of the subclasses?

1
3
3/14/2017 2:31:37 PM

Accepted Answer

Update: Starting with version 2.1, Include on derived types is now naturally supported by EF Core via either cast or as operator inside lambda Include / ThenInclude overloads or string Include overload.

Original answer (pre EF Core 2.1):

Currently eager loading of derived entity navigation properties is not supported.

As a workaround you can use a combination of Eager loading, Explicit loading and Querying related entities explained in the Loading Related Data section of the EF Core documentation:

var user = _users.Include(u => u.Role).SingleOrDefault(u => u.UserId == id);
var userRoleQuery = db.Entry(user).Reference(u => u.Role).Query();
if (user.Role is ManagerUserRole)
    userRoleQuery.OfType<ManagerUserRole>().Include(r => r.Groups).Load();
else if (user.Role is PersonUserRole)
    userRoleQuery.OfType<PersonUserRole>().Include(r => r.Group).Load();
return user;
5
6/20/2018 8:24:10 AM

Popular Answer

EntityFramework has an open issue which is exacly the same as your problem: https://github.com/aspnet/EntityFramework/issues/3910

Maybe you can try what they suggest, but I can't try if it works:

var o = context.Set<Order>()
    .Where(o => o.Id == 1234)
    .Single();

context.Set<GroupPosition>()
    .Where(x => x.Order == o)
    .Include(x => x.GroupType)
    .Load();

context.Set<SalesPosition>()
    .Where(x => x.Order == o)
    .Include(x => x.Group)
    .Load();


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow