Given the following class structure
public class Parent
{
public Guid Id { get;
public List<BaseChild> Children { get; set; }
}
public abstract class BaseChild
{
public int Id { get; set; }
public string ChildName { get; set; }
}
public class NormalChild : BaseChild
{
public DateTime BirthDate { get; set; }
}
public class RichChild : BaseChild
{
public List<OffshoreAccount> OffshoreAccounts { get; set; }
}
public class OffshoreAccount
{
public string AccountNumber { get; set; }
public AccountInfo AccountInfo { get; set; }
}
What is the best way to query parent data to include information about the children's offshore accounts?. I came up with the solution below, using ef-core's explicit loading, but it just doesn't feel right. Is there a more elegant solution?
var parent = Context.Set<Parent>()
.Where(o => o.Id == Guid.Parse(parentId))
.Include(o => o.Children)
.SingleOrDefault();
foreach (var child in parent.Children.OfType<RichChild>())
{
Context.Entry<RichChild>(child).Collection(f => f.OffshoreAccounts).Load();
foreach (var account in child.OffshoreAccounts)
{
Context.Entry<OffshoreAccount>(account).Reference(f => f.AccountInfo).Load();
}
}
Currently there is no way to accomplish that in the parent query, but the explicit loading can be improved by using a combination of Entry
, Collection
, Query
, Include
/ ThenInclude
and Load
calls:
var parent = Context.Set<Parent>()
.Where(o => o.Id == Guid.Parse(parentId))
.Include(o => o.Children)
.SingleOrDefault();
Context.Entry(parent).Collection(e => e.Children)
.Query().OfType<RichChild>()
.Include(e => e.OffshoreAccounts)
.ThenInclude(e => e.AccountInfo)
.Load();
In the current EFCore (2.1.1) you can use type casting in ThenInclude
to get the results you're looking for:
var parent = _context.Set<Parent>()
.Include(x => x.Children)
.ThenInclude(y => (y as RichChild).OffshoreAccounts)
.SingleOrDefault();