EF Core SQL 带有 Linq 表达式的函数 LIKE 方法不适用于非字符串类型

EF Core SQL Function LIKE Method with Linq Expression not working for Non String types

我能够使用 SQL 函数创建调用表达式,如下所示

var likeMethod = typeof(DbFunctionsExtensions).GetMethod("Like", new[] { typeof(DbFunctions), typeof(string), typeof(string) });

Expression.Call(null, likeMethod, Expression.Constant(EF.Functions), searchKeyExpression, Expression.Constant($"%{filter.Value}%"));

我只需要了解如何将整数或小数列等列的功能与 Like 函数一起使用。 如果我使用上面的表达式,我会得到以下错误。我如何像使用非字符串数据类型

一样使用带有 ef 的表达式

Argument Exeption: argument exception in Expression of System.Int32 can not be used for parameter for type System.String of method Boolean Like (Ef.DBfuntions)

重现步骤

var likeMethod = typeof(DbFunctionsExtensions).GetMethod("Like", new[] { typeof(DbFunctions), typeof(string), typeof(string) });

Expression.Call(null, likeMethod, Expression.Constant(EF.Functions), searchKeyExpression, Expression.Constant($"%{filter.Value}%"));

正如我所看到的,在下面的示例中的 Ef.Functions Like 方法中有一个选项

context.Set<MyEntity>().Where(e => EF.Functions.Like((string)(object)e.IntCol, "%1%"))

但是我如何使用成员表达式来做到这一点。

来源:- https://github.com/aspnet/EntityFrameworkCore/issues/9578

这是直线查询的解决方案。 https://github.com/aspnet/EntityFrameworkCore/issues/16195

更多技术细节

EF 核心版本:(ASP.NET 核心 2.1) 数据库提供者:(例如 Microsoft.EntityFrameworkCore.SqlServer) 操作系统: IDE:(例如 Visual Studio 2017 15.4)

"double cast" (string)(object)e.IntCol 是一种欺骗 C# 编译器将 "pass" int 参数传递给需要 string 参数的方法(如 EF.Functions.Like).当然,如果实际调用了该方法,您将在运行时得到无效的强制转换异常。

但这个技巧奏效了,因为像这样的方法永远不会 "called",而是转换为 SQL,并且 SqlServer EF Core 提供程序删除了此类转换并允许您使用 SqlServer 隐式数据转换。我在 and .

中使用相同的技术(尽管方向相反)

这是映射到 Expression 方法的方式。给定 Expression searchKeyExpression(具体的 Expression 类型无关紧要),重要的是 Expression.Type 属性 返回的 Type。如果它是 string,你没问题,否则你需要对其应用 (string)(object) 强制转换,这是通过两次 Expression.Convert 调用实现的。

像这样:

Expression matchExpression = searchKeyExpression;
if (matchExpression.Type != typeof(string))
{
    matchExpression = Expression.Convert(matchExpression, typeof(object));
    matchExpression = Expression.Convert(matchExpression, typeof(string));
}
var pattern = Expression.Constant($"%{filter.Value}%");
var callLike = Expression.Call(
    typeof(DbFunctionsExtensions), "Like", Type.EmptyTypes,
    Expression.Constant(EF.Functions), matchExpression, pattern);