我使用此代码,但它得到一个错误:

错误:System.ArgumentException:类型为‘...GreenPaperItem’的表达式不能用于方法‘Boolean’的类型为‘System.Runime.CompilerServices.Cloure’的参数

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

该表达式用于Linq to Entities IQueriyable查询:

 query = query.Where(ToExpression<GreenPaperItem>(filter.GenerateFilterFunction()));

推荐答案

如何将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)的行为也证明了这一点.

您有几个选项:

  1. 引入GenerateFilterExpression方法,它将实际构建可翻译的Expression<Func<T, bool>>

  2. 很常见的方法就是利用自己的能力来"动态"地组成Where‘S(当你需要的时候和组合逻辑):

    if(filter.IsProp1Provided)
    {
        query = query.Where(e => e.Col1 == filter.Prop1);
    }
    
    if(filter.IsAnotherPropProvided)
    {
        query = query.Where(e => e.AnotherCol == filter.AnotherProp);
    }
    
  3. 使用PredicateBuilder from LINQKit(可能除了点2之外)

另见:

Csharp相关问答推荐

System.Data.SQLite:判断SQLite数据库是否为空(任何表中至少有一行)

Monty Hall游戏节目模拟给我50/50的结果

如何注销Microsoft帐户?

碰撞检测与盒碰撞器,其isTrigger on问题

Blazor服务器端的身份验证角色

C#方法从AJAX调用接收NULL

如何在毛伊岛应用程序中完美地同步视图模型和视图的加载?

使用Dapper映射联接查询对象数据到使用SplitOn;

C#Null判断处理失败

ASP.NET Core MVC将值从视图传递到控制器时出现问题

有没有更好的方法来在CosmosDB上插入非id?

如何在.NET AOT中为所有枚举启用JsonStringEnumConverter

在使用UserManager时,如何包含与其他实体的关系?

发布.NET 8 Blazor WebAssembly独立应用程序以进行静态站点部署

C#使用相同内存的多个数组

工厂类是如何在.NET 8中注册的?

ASP.NET Core 8 Web API:如何添加版本控制?

避免在特定区域中设置Visual Studio代码的自动格式

S,在.NET核心控制台应用程序中,AddScope和AddSingleton有什么不同?

在C#中删除多个不同名称的会话