首页 > 解决方案 > 为什么没有 EF Core OfType(Type type) 方法?

问题描述

我目前使用的是 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;}

我想实现这样的代码:

var getInheritedSet = dbSet.OfType(typeIStronglyNeed);

但我只能做这样的事情:

var getInheritedSet1 = dbSet.OfType<Foo>;
var getInheritedSet2 = dbSet.OfType<Bar>;

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

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

谢谢你。

标签: c#.net-coreentity-framework-core

解决方案


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

没有标准OfType(Type)方法,EF Core 设计人员也没有找到实现这种自定义 EF Core 特定扩展的理由。

但实施起来并不难。TPH(和其他未来的数据库继承策略)在 LINQ to Entities 查询中由is和运算符支持。所以你需要的是相当于ascast

Where((BaseClass e) => e is some_type)

这样的表达式不能在编译时创建,但可以使用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);
}

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

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

var entityType = dbContext.Model.FindEntityType(typeof(BaseClass));

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

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

推荐阅读