6

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?

3
  • What if you try .ThenInclude(r => ((PersonUserRole)r).Group) ? Commented Mar 9, 2017 at 20:35
  • @Mangist I'm afraid this returns a "Value cannot be null. Parameter name: source" error. But I can't seem to find what the issue is. Commented Mar 9, 2017 at 21:25
  • It's null if your object can't be cast to a PersonUserRole. I'd personally just do this without LINQ Commented Mar 10, 2017 at 0:55

2 Answers 2

8

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;
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the solution! I'm trying it out, however, I can't seem to find the Reference method. Could you perhaps nudge me in the right direction?
FYI link in the update has moved to learn.microsoft.com/en-us/ef/core/querying/related-data/… . I would've edited but queue is full at time of comment
@Luke Shame on them, link breakers! Just kidding, thank you for pointing out, link updated.
A constant battle, isn't it? ;) Thanks for the fix!
2

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();

1 Comment

This solution is (highly) preferable to accepted one when multiple entities are requested.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.