Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
466 views
in Technique[技术] by (71.8m points)

c# - ef-core load collection property of nested tph inherited member

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();
            }
     }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Update (EF Core 2.1+):

Starting with v2.1, EF Core native supports Include on derived types through C# cast or as operators.

e.g

.Include(e => e.Children)
    .ThenInclude(e => ((RichChild)e).OffshoreAccounts)
        .ThenInclude(e => e.AccountInfo)

or

.Include(e => e.Children)
    .ThenInclude(e => (e as RichChild).OffshoreAccounts)
        .ThenInclude(e => e.AccountInfo)

The documentation claims that the string overload of Include coudld also be used, e.g. according to it

.Include(e => "Children.OffshoreAccounts.AccountInfo")

should also work, but it doesn't (checked up to v3.1.4).

Original:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...