Wil*_*llC 4 c# entity-framework discriminator entity-framework-core .net-core
默认情况下,EF6 将为每个层次结构表 (TPH) 映射一个基本抽象类及其派生类。
EF Core 不再遵循此逻辑,并要求选择派生类。文档指出:
按照约定,上下文中的 DbSet 属性中公开的类型将作为实体包含在模型中。还包括 OnModelCreating 方法中指定的实体类型,以及通过递归探索其他已发现实体类型的导航属性找到的任何类型。
如果您有一些子类型,那么使用这种方法并不难,因为您可以将它们添加为 DbSet,或者为每个子类型添加 HasDiscriminator().HasValue() ,映射如下:
builder.HasDiscriminator()
.HasValue<CommaSymbolRule>("CommaSymbolRule")
.HasValue<DashSymbolRule>("DashSymbolRule")
.HasValue<IsNumericSymbolRule>("IsNumericSymbolRule")
.HasValue<IsPunctuationSymbolRule>("IsPunctuationSymbolRule")
.HasValue<PeriodSymbolRule>("PeriodSymbolRule")
Run Code Online (Sandbox Code Playgroud)
在某些情况下,这是次优的,因为您可能有许多派生类。就我而言,我有一个规则引擎,并且不想单独映射每个规则。
有没有办法在 EF Core Table Per Hierarchy 场景中自动映射基类的子类型,而无需手动添加它们?
我以为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();
}
Run Code Online (Sandbox Code Playgroud)
然后对 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);
}
}
Run Code Online (Sandbox Code Playgroud)
foreach 从基类获取派生类并循环它们,并为每个派生类添加一个鉴别器类型。