I currently use EF Core 3.0. So, I want to realize TPH model data selection through the base table requesting. Let's see the example:
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;}
And I want to implement code like this:
var getInheritedSet = dbSet.OfType(typeIStronglyNeed);
But I can only do something like this:
var getInheritedSet1 = dbSet.OfType<Foo>;
var getInheritedSet2 = dbSet.OfType<Bar>;
Could you explain why EF Core 3.0 has no OfType(Type type)
but only OfType<TType>()
?
And the second question - how is it possible to get inherited data types from DbSet?
Thank you.
The generic method OfType<T>
is a standard LINQ method which EF Core supports.
There is no standard OfType(Type)
method and EF Core designers didn't find a reason of implementing such custom EF Core specific extension.
But it's not hard to be implemented. TPH (and other future database inheritance strategies) are supported in LINQ to Entities queries by is
, as
and cast
operators. So what you need is the equivalent of
Where((BaseClass e) => e is some_type)
Such expression cannot be created at compile time, but can easily be created using the Expression
class methods (in particular Expression.TypeIs) like this:
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);
}
And the second question - how is it possible to get inherited data types from DbSet?
EF Core metadata is exposed through DbContext.Model
property. You can use FindEntityType
to get the IEntityType
describing the entity type
var entityType = dbContext.Model.FindEntityType(typeof(BaseClass));
and now there are a lot of available methods regarding inheritance like GetDerivedTypes
, GetDerivedTypesInclusive
, GetDirectlyDerivedTypes
, GetConcreteDerivedTypesInclusive
etc. The last one can be used to retrieve the whole TPH hierarchy excluding the abstract types. And also GetDiscriminatorProperty
and GetDiscriminatorValue
to get the discriminator column name, type and value for each entity in the TPH. For instance
var discriminatorProperty = entityType.GetDiscriminatorProperty();
var typeInfo = entityType
.GetConcreteDerivedTypesInclusive()
.Select(t => new
{
Type = t,
DiscriminatorValue = t.GetDiscriminatorValue()
})
.ToList();