如何将Func<T, bool>
转换为Expression<Func<T, bool>>
简而言之,你不需要.反之亦然,通过框架Expression<TDelegate>.Compile
方法提供的转换是"容易的".但另一方面,需要执行类似于从IL/机器码反编译之类的操作(我想我看到了一些try ,但不确定何时何地).
我使用了AsQueryable()
,它是有效的,但是为了判断它在最后是否不可枚举,我得到了一个错误:"给定的‘IQueryable’不支持查询字符串的生成."当我想要转换查询ToQueryString()
时
因此,基本上它不起作用(至少在你实际想要/需要的方式上是这样).
看来你对IQueryable
、表达式树和查询提供程序(尤其是EF Core)的工作原理有一些误解.简而言之(经过一些简化),通常查询提供程序将分析传递的表达式树 来执行一些操作.在EF Core的情况下,它会将调用转换为实际的SQL查询,它不能将任意方法调用转换为SQL,这不能通过将filter.GenerateFilterFunction()
返回的Func<...>
"转换"为Expression<Func<...>>
来解决.
您的try 不起作用:
public static Expression<Func<T, bool>> ToExpression<T>(Func<T, bool> p)
{
ParameterExpression p0 = Expression.Parameter(typeof(T));
ParameterExpression p1 = Expression.Parameter(typeof(bool));
return Expression.Lambda<Func<T, bool>>(Expression.Call(p.Method, p0, p1),
new ParameterExpression[] { p0, p1 });
}
与:没有太大不同:
query.Where(gpi => filter.GenerateFilterFunction()(gpi)) // allow the compiler to do the magic for you
这将有同样的问题- GenerateFilterFunction
返回函数查询提供程序(EF核心)一无所知,不能将其转换为SQL(原因很明显).
以及你在 comments 中的try :
query = query
.Where(filter.GenerateFilterFunction())
.AsQueryable();
将导致从.Where(filter.GenerateFilterFunction())
开始的所有内容都将在客户端执行,并将所有内容提取到内存中,而不会在数据库端进行过滤(将使用Enumerable.Where(Func<>)
而不是Queryable.Where(Expression<Func<>>)
,基本上与Where
之前的显式AsEnumerable()
调用的效果相同).下面的AsQueryable
没有任何显著影响,因为它将可在内存中对象上进行查询.观察到的EntityFrameworkQueryableExtensions.ToQueryString(IQueryable)
的行为也证明了这一点.
您有几个选项:
引入GenerateFilterExpression
方法,它将实际构建可翻译的Expression<Func<T, bool>>
很常见的方法就是利用自己的能力来"动态"地组成Where
‘S(当你需要的时候和组合逻辑):
if(filter.IsProp1Provided)
{
query = query.Where(e => e.Col1 == filter.Prop1);
}
if(filter.IsAnotherPropProvided)
{
query = query.Where(e => e.AnotherCol == filter.AnotherProp);
}
使用PredicateBuilder
from LINQKit(可能除了点2之外)
另见: