嵌套 tph 继承成员的 ef-core 负载收集属性

Posted

技术标签:

【中文标题】嵌套 tph 继承成员的 ef-core 负载收集属性【英文标题】:ef-core load collection property of nested tph inherited member 【发布时间】:2017-01-13 14:39:31 【问题描述】:

给定以下类结构

 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; 
    

查询父母数据以包含子女离岸账户信息的最佳方式是什么?我想出了下面的解决方案,使用 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();
            
     

【问题讨论】:

请将childs重命名为children 什么是AccountInfo 为了避免加载相关实体的代码开销,您应该让 EF 通过启用 EF 延迟加载或急切加载来完成这项工作。在这里查看更多信息:msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx @Felix 目前 EF Core 中没有延迟加载,也没有急切加载派生类属性的语法。 【参考方案1】:

更新(EF Core 2.1+):

从 v2.1 开始,EF Core 原生支持 Include on derived types 通过 C# cast 或 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)

文档声称Includestring 重载也可以使用,例如根据它

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

应该也可以,但它没有(检查到 v3.1.4)。

原文:

目前无法在父查询中实现这一点,但可以通过使用EntryCollectionQueryInclude/ThenInclude 和@987654335 的组合来改进显式加载@调用:

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

【讨论】:

我怎样才能将它扩展到更低的 tph?为了给出上下文,我有以下结构(在表单构建器上工作): Form.Questions.Control 控件是下拉或 TextField 等类的基本类型。 @Peter-Paul 所以你想包含控制的部分吗?我不能确切地说 - 因为上面是某种黑客,因此一般不可扩展,您可以考虑使用示例 minimal reproducible example 发布您自己的具体问题。 我最终做到了,首先获取表单,然后遍历问题以逐个控件添加特定于类的属性。很多数据库调用,但它完成了工作。 @IvanStoev 你有提到这个的 github 问题链接或文档吗? @Dealdiane #3910【参考方案2】:

在当前的 EFCore (2.1.1) 中,您可以在 ThenInclude 中使用类型转换来获得您正在寻找的结果:

var parent = _context.Set<Parent>()
                 .Include(x => x.Children)
                 .ThenInclude(y => (y as RichChild).OffshoreAccounts)
                 .SingleOrDefault();

【讨论】:

以上是关于嵌套 tph 继承成员的 ef-core 负载收集属性的主要内容,如果未能解决你的问题,请参考以下文章

EF-core如何建立与“自身”的many2many关系

Entity Framework 6 Recipes 2nd Edition(10-10)译 - > 为TPH继承的插入更新删除操作映射到存储过程

EF Core从TPH迁移到TPT

如何使 EF-Core 使用 Guid 而不是 String 作为其 ID/主键

继承 Java 私有成员

面向对象---成员,嵌套(建模)