如何在EF Core中自动映射TPH派生类?

3

缺省情况下,EF6 采用表继承的方法来映射基础抽象类及其派生类。

然而 EF Core 不再遵循这一逻辑,需要明确选择要包含的派生类。文档中指出:

按照惯例,在上下文中公开的 DbSet 属性中公开的类型将作为实体包含在模型中。在 OnModelCreating 方法中指定的实体类型也将被包括在内,以及通过递归地探索其他发现的实体类型的导航属性找到的任何类型。

如果您只有几个子类型,使用此方法不会太难,只需将它们添加为 DbSets 或添加一个 HasDiscriminator().HasValue(),并按以下方式进行映射:

builder.HasDiscriminator()
    .HasValue<CommaSymbolRule>("CommaSymbolRule")
    .HasValue<DashSymbolRule>("DashSymbolRule")
    .HasValue<IsNumericSymbolRule>("IsNumericSymbolRule")
    .HasValue<IsPunctuationSymbolRule>("IsPunctuationSymbolRule")
    .HasValue<PeriodSymbolRule>("PeriodSymbolRule")

在某些情况下,这可能不是最佳选择,因为您可能有许多派生类。在我的情况下,我有一个规则引擎,不想每个规则都要进行映射。是否有一种方法可以在EF Core Table Per Hierarchy场景中自动映射基类的子类型而无需手动添加它们?
1个回答

6

我认为在EF Core中可能有一种方法可以做到这一点,但是发现并没有。

我与EF团队讨论了为什么自动加入不再是默认设置,他们提出了关于"程序集扫描解决方案"稳定性的担忧,这些担忧可能是非常合理的。他们似乎对此时添加类似功能的新特性不太感兴趣。

这是我想到的替代方法。它将程序集扫描放置在映射代码中,看起来能够正常工作。

首先,我创建了一个扩展方法来获取派生类(该方法还可以选择忽略特定名称的类型):

public static Type[] GetDerivedClasses(this Type type, string[] ignoreTypeNames = null) 
{
    ignoreTypeNames = ignoreTypeNames ?? new string[0];

    return Assembly.GetAssembly(type)
                    .GetTypes()
                    .Where
                    (
                        t => t.IsSubclassOf(type) &&
                        (!ignoreTypeNames?.Any(t.Name.Contains) ?? false)
                    )
                    .OrderBy(o => o.Name)
                    .ToArray();
}

然后在 EF Core 映射的基类中使用类似以下代码,将类型替换为您自己的类型(例如,在此代码中,“SymbolRule”):

public void Configure(EntityTypeBuilder<SymbolRule> builder)
{
    builder.ToTable("SymbolRule");       // my example table
    builder.HasKey(t => t.SymbolRuleId); // my example key


    foreach (var type in typeof(SymbolRule).GetDerivedClasses())
    {
        builder.HasDiscriminator()
               .HasValue(type, type.Name);
    }
}

foreach 从基类获取派生类并循环遍历它们,为每个添加鉴别器类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接