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);
我能够使用 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 隐式数据转换。我在
这是映射到 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);