如何在EF Core中自动映射TPH派生类? [英] How to Automatically Map TPH Derived Classes in EF Core?

查看:58
本文介绍了如何在EF Core中自动映射TPH派生类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

默认情况下,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") 

在某些情况下,这是次优的,因为您可能有许多派生类.就我而言,我有一个规则引擎,并且不想单独映射每个规则.

是否有一种方法可以自动映射EF Core Table Per Hierarchy方案中的基类的子类型,而不必手动添加它们?

解决方案

我认为EF Core中可能有这样做的方法,但是发现没有.

我与EF团队讨论了为什么自动选择加入不再是默认选择,并且他们对装配扫描解决方案"的稳定性表示担忧.这可能是非常有效的.目前,他们似乎不太想在这些方面增加新功能.

这是我想出的.它将程序集扫描放入映射代码中,但似乎可以正常工作.

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

 公共静态Type [] GetDerivedClasses(此类型类型,字符串[] ignoreTypeNames = null){ignoreTypeNames = ignoreTypeNames ??新字符串[0];返回Assembly.GetAssembly(type).GetTypes().在哪里(t =>t.IsSubclassOf(type)&&(!ignoreTypeNames?.Any(t.Name.Contains)?? false)).OrderBy(o => o.Name).ToArray();} 

然后在EF Core映射中对基类使用与此类似的代码,切换出您的类型(即此代码中的"SymbolRule"):

  public void Configure(EntityTypeBuilder< SymbolRule>构建器){builder.ToTable("SymbolRule");//我的示例表builder.HasKey(t => t.SymbolRuleId);//我的示例密钥foreach(typeof(SymbolRule).GetDerivedClasses()中的var类型){builder.HasDiscriminator().HasValue(type,type.Name);}} 

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

By default, EF6 would map a base abstract class and it's derived classes for Table Per Hierarchy (TPH).

EF Core no longer follows this logic and requires derived classes to be opted in. The documentation states:

By convention, types that are exposed in DbSet properties on your context are included in the model as entities. Entity types that are specified in the OnModelCreating method are also included, as are any types that are found by recursively exploring the navigation properties of other discovered entity types.

Using this approach is not too hard to follow if you have a few sub-types as you can just add them as DbSets or add a HasDiscriminator().HasValue() for each sub-type with mapping as below:

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

In some circumstances this is a sub-optimal as you may have many derived classes. In my case, I have a rules engine and do not want to have map each rule individually.

Is there a way to automatically map the sub-types of a base class in an EF Core Table Per Hierarchy scenario without having to manually add them?

解决方案

I thought there may be a way to do this in EF Core, but found that there was not one.

I discussed with the EF team why automatic opt-in is no longer the default and they gave concerns about the stability of "assembly scanning solutions" which are probably very valid. They did not seem too interested in adding a new feature along those lines at this moment.

Here is what I came up with instead. It puts the assembly scanning in the mapping code but seems to work.

First, I created an extension method to get the derived classes (which optionally can ignore particular types by name):

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

Then use code similar to this for the base class in the EF Core mapping, switching out your type (ie: "SymbolRule" in this code):

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

The foreach gets the derived classes from the base class and loops through them and adds a discriminator type for each.

这篇关于如何在EF Core中自动映射TPH派生类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆