[英]Build expression tree with generic class for EF Core
I have a TPH architecture with the following hierarchy:我有一个具有以下层次结构的 TPH 架构:
abstract class Task
{
public int A { get; set; }
}
abstract class DocumentTask
{
public virtual Document Doc { get;set; }
public int B { get; set; }
}
class DocumentTask<TDocument> : DocumentTask
where TDocument : Document, new()
{
public override TDocument Doc { get; set; }
}
/* Some classes are inherited from DocumentTask<TDocument> */
class SignTask<TDocument> : DocumentTask<TDocument>
where TDocument : Document, new()
{
public int C { get;set; }
}
And I need to get all SignTask
from the database with the specified C
.我需要使用指定的SignTask
从数据库中获取所有C
。 But as I don't have non-generic SignTask, I cannot do something like that db.Where(t => t is SignTask && ((SignTask)t).C == 5)
.但是因为我没有非通用的 SignTask,所以我不能做类似的事情db.Where(t => t is SignTask && ((SignTask)t).C == 5)
。 That's why I decided to build an Expression tree directly and it works to get entities only of SignTask<> type:这就是为什么我决定直接构建一个表达式树并且它只用于获取 SignTask<> 类型的实体:
var taskTypes = typeof(SignTask<>).Assembly
.GetTypes()
.Where(t =>
(t?.BaseType?.IsGenericType ?? false)
&& t?.BaseType?.GetGenericTypeDefinition() == typeof(SignTask<>)).ToList();
var parameter = Expression.Parameter(typeof(Task), "e");
var body = taskTypes.Select(type => Expression.TypeIs(parameter, type))
.Aggregate<Expression>(Expression.OrElse);
var predicate = Expression.Lambda<Func<Task, bool>>(body, parameter);
var tasks = await _dbContext
.Tasks
.Where(predicate)
.ToArrayAsync();
But I cannot filter it by the C
property, as I cannot build Expression.Parameter
for generic type without a specified generic argument.但是我无法通过C
属性对其进行过滤,因为我无法在没有指定泛型参数的情况下为泛型类型构建Expression.Parameter
。 Is there a way to implement this query?有没有办法实现这个查询?
If DocumentTask
is derived from Task
, you can do the following:如果DocumentTask
派生自Task
,您可以执行以下操作:
var parameter = Expression.Parameter(typeof(Task), "e");
var valueExpr = Expression.Constant(c);
var body = taskTypes.Select(type => Expression.AndAlso(Expression.TypeIs(parameter, type),
Expression.Equal(
Expression.Property(Expression.Convert(parameter, type), nameof(SignTask<Document>.C)),
valueExpr)))
.Aggregate<Expression>(Expression.OrElse);
var predicate = Expression.Lambda<Func<Task, bool>>(body, parameter);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.