如何将 Func<T, bool> 转换为表达式<Func<T, bool>>

问题描述 投票:0回答:1

我使用此代码,但出现错误:

错误:System.ArgumentException:“...GreenPaperItem”类型的表达式不能用于方法“Boolean”的“System.Runtime.CompilerServices.Closure”类型的参数

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 });
}

该表达式旨在用于实体 IQueriyable 查询的 linq:

 query = query.Where(ToExpression<GreenPaperItem>(filter.GenerateFilterFunction()));
c# lambda entity-framework-core expression
1个回答
0
投票

如何将

Func<T, bool>
转换为
Expression<Func<T, bool>>

简而言之 - 你不知道。反之亦然,通过框架

Expression<TDelegate>.Compile
方法提供的转换是“容易”的。但其他方法将需要执行诸如从 IL/机器代码反编译之类的操作(我想我看到了一些尝试)。

我使用了 AsQueryable() 并且它有效,但是为了检查它最后是否不可枚举,我收到错误“给定的‘IQueryable’不支持生成查询字符串。”当我想将查询转换为ToQueryString()

所以基本上它不起作用(至少以你想要/需要的方式),它只是编译。

您似乎对

IQueryable
、表达式树和查询提供程序(尤其是 EF Core 之一)的工作方式存在一些误解。简而言之(经过一些简化)通常查询提供程序将分析传递的表达式树以执行某些操作。在 EF Core 情况下,它会将调用转换为实际的 SQL 查询(对于数据库),并且无法将任意方法调用转换为 SQL,这基本上就是您试图通过“转换”由
Func<...> 返回的 
filter.GenerateFilterFunction()
 来实现的操作
Expression<Func<...>>
。您的尝试与以下内容没有太大不同:

query.Where(gpi => filter.GenerateFilterFunction()(gpi)) // allow the compiler to do the magic for you

这将有同样的问题 -

GenerateFilterFunction
返回函数查询提供程序(EF Core)一无所知,并且无法将其转换为 SQL(出于明显的原因)。

所以你的尝试:

query = query
   .Where(filter.GenerateFilterFunction())
   .AsQueryable();

将导致自

.Where(filter.GenerateFilterFunction())
以来的所有内容都将在客户端执行,将所有内容提取到内存中,而不在数据库端进行过滤(将使用
Enumerable.Where(Func<>)
而不是
Queryable.Where(Expression<Func<>>)
,与显式效果基本相同)
AsEnumerable()
先打电话
Where
)。以下
AsQueryable
没有任何显着效果,因为它将可通过内存中的对象进行查询。

该做什么:

  1. 您有多种选择 - 引入

    GenerateFilterExpression
    方法,该方法将实际构建可翻译的
    Expression<Func<T, bool>>

  2. 非常常见的方法是利用“动态”撰写

    Where
    的能力:

    if(filter.IsProp1Provided)
    {
        query = query.Where(e => e.Col1 == filter.Prop1);
    }
    if(filter.IsAnotherPropProvided)
    {
        query = query.Where(e => e.AnotherCol == filter.AnotherProp);
    }
    
  3. 使用 LINQKit 中的

    PredicateBuilder(可能除了第 2 点之外)

另请参阅:

© www.soinside.com 2019 - 2024. All rights reserved.