ef-core 加载嵌套 tph 继承成员的集合 属性
ef-core load collection property of nested tph inherited member
给定以下 class 结构
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; }
}
查询 parent 数据以包含 children 离岸账户信息的最佳方式是什么?。我想出了下面的解决方案,使用 ef-core 的显式加载,但感觉不对。有没有更优雅的解决方案?
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();
}
}
更新(EF Core 2.1+):
从 v2.1 开始,EF Core 本机支持 Include on derived types 通过 C# 转换或 as
运算符。
例如
.Include(e => e.Children)
.ThenInclude(e => ((RichChild)e).OffshoreAccounts)
.ThenInclude(e => e.AccountInfo)
或
.Include(e => e.Children)
.ThenInclude(e => (e as RichChild).OffshoreAccounts)
.ThenInclude(e => e.AccountInfo)
文档声称 Include
的 string
重载也可以使用,例如据此
.Include(e => "Children.OffshoreAccounts.AccountInfo")
应该也可以,但它没有(检查到 v3.1.4)。
原文:
目前无法在父查询中实现这一点,但可以通过组合使用 Entry
、Collection
、Query
、[= 来改进显式加载16=] / ThenInclude
和 Load
调用:
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();
在当前的 EFCore (2.1.1) 中,您可以在 ThenInclude
中使用类型转换来获得您要查找的结果:
var parent = _context.Set<Parent>()
.Include(x => x.Children)
.ThenInclude(y => (y as RichChild).OffshoreAccounts)
.SingleOrDefault();
给定以下 class 结构
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; }
}
查询 parent 数据以包含 children 离岸账户信息的最佳方式是什么?。我想出了下面的解决方案,使用 ef-core 的显式加载,但感觉不对。有没有更优雅的解决方案?
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();
}
}
更新(EF Core 2.1+):
从 v2.1 开始,EF Core 本机支持 Include on derived types 通过 C# 转换或 as
运算符。
例如
.Include(e => e.Children)
.ThenInclude(e => ((RichChild)e).OffshoreAccounts)
.ThenInclude(e => e.AccountInfo)
或
.Include(e => e.Children)
.ThenInclude(e => (e as RichChild).OffshoreAccounts)
.ThenInclude(e => e.AccountInfo)
文档声称 Include
的 string
重载也可以使用,例如据此
.Include(e => "Children.OffshoreAccounts.AccountInfo")
应该也可以,但它没有(检查到 v3.1.4)。
原文:
目前无法在父查询中实现这一点,但可以通过组合使用 Entry
、Collection
、Query
、[= 来改进显式加载16=] / ThenInclude
和 Load
调用:
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();
在当前的 EFCore (2.1.1) 中,您可以在 ThenInclude
中使用类型转换来获得您要查找的结果:
var parent = _context.Set<Parent>()
.Include(x => x.Children)
.ThenInclude(y => (y as RichChild).OffshoreAccounts)
.SingleOrDefault();