为什么EF Core没有OfType(Type type)方法?

Dmi*_*riy 3 c# entity-framework-core .net-core

我目前使用 EF Core 3.0。所以,我想通过基表请求来实现TPH模型数据选择。让我们看一下例子:

public class BaseClass
{
   public int Base {get;set;}
}

public class Foo : BaseClass
{
   public int FooMember {get;set;}
}

public class Bar : BaseClass
{
  public int BarMember {get;set;}
}

public DbSet<BaseClass> dbSet {get;set;}
Run Code Online (Sandbox Code Playgroud)

我想实现这样的代码:

var getInheritedSet = dbSet.OfType(typeIStronglyNeed);
Run Code Online (Sandbox Code Playgroud)

但我只能做这样的事情:

var getInheritedSet1 = dbSet.OfType<Foo>;
var getInheritedSet2 = dbSet.OfType<Bar>;
Run Code Online (Sandbox Code Playgroud)

您能解释一下为什么 EF Core 3.0 没有OfType(Type type)but only 吗OfType<TType>()

第二个问题——如何从 DbSet 获取继承的数据类型?

谢谢。

Iva*_*oev 6

通用方法OfType<T>是 EF Core 支持的标准 LINQ 方法。

没有标准OfType(Type)方法,EF Core 设计者也没有找到实现此类自定义 EF Core 特定扩展的原因。

但实施起来并不难。isLINQ to Entities 查询中通过,as和运算符支持 TPH(以及其他未来的数据库继承策略)cast。所以你需要的是相当于

Where((BaseClass e) => e is some_type)
Run Code Online (Sandbox Code Playgroud)

Expression这样的表达式无法在编译时创建,但可以使用类方法(特别是Expression.TypeIs )轻松创建,如下所示:

public static IQueryable<T> OfType<T>(this IQueryable<T> source, Type type)
{
    var parameter = Expression.Parameter(typeof(T), "e");
    var body = Expression.TypeIs(parameter, type);
    var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
    return source.Where(predicate);
}
Run Code Online (Sandbox Code Playgroud)

第二个问题——如何从 DbSet 获取继承的数据类型?

EF Core 元数据通过属性公开DbContext.Model。您可以使用FindEntityType来获取IEntityType描述实体类型

var entityType = dbContext.Model.FindEntityType(typeof(BaseClass));
Run Code Online (Sandbox Code Playgroud)

现在有很多关于继承的可用方法,如GetDerivedTypesGetDerivedTypesInclusiveGetDirectlyDerivedTypesGetConcreteDerivedTypesInclusive。最后一种可用于检索整个 TPH 层次结构(不包括抽象类型)。并且还GetDiscriminatorProperty获取GetDiscriminatorValueTPH 中每个实体的鉴别器列名称、类型和值。例如

var discriminatorProperty = entityType.GetDiscriminatorProperty();
var typeInfo = entityType
    .GetConcreteDerivedTypesInclusive()
    .Select(t => new
    {
        Type = t,
        DiscriminatorValue = t.GetDiscriminatorValue()
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)