C# 具有Linq表达式的EF核心SQL类函数方法不适用于非字符串类型

C# 具有Linq表达式的EF核心SQL类函数方法不适用于非字符串类型,c#,entity-framework-core,expression-trees,ef-core-2.1,C#,Entity Framework Core,Expression Trees,Ef Core 2.1,我能够使用如下所示的SQL函数创建调用表达式 var likeMethod = typeof(DbFunctionsExtensions).GetMethod("Like", new[] { typeof(DbFunctions), typeof(string), typeof(string) }); Expression.Call(null, likeMethod, Expression.Constant(EF.Functions), searchKeyExpression, Express

我能够使用如下所示的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}%"));
我只需要了解如何使用integer或decimal column等列的功能来与类似的函数一起使用。 如果我使用上面的表达式,我得到下面的错误。如何将表达式与ef-like一起用于非字符串数据类型

参数异常:System.Int32表达式中的参数异常不能用于类布尔(Ef.dbFunctions)方法的System.String类型的参数

复制步骤
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中有一个选项,比如下面示例中的method

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

context.Set().Where(e=>EF.Functions.Like((string)(object)e.IntCol,“%1%”)
但是如何使用成员表达式来实现这一点呢

资料来源:

这是直线查询的解决方案。

进一步的技术细节 EF核心版本:(ASP.NET核心2.1) 数据库提供程序:(例如Microsoft.EntityFrameworkCore.SqlServer) 操作系统: IDE:(例如Visual Studio 2017 15.4)

双模式转换
(字符串)(对象)e.IntCol
是一种欺骗C#编译器将
int
参数“传递”给需要
字符串
参数的方法(如
EF.Functions.like
)。当然,如果实际调用了该方法,则在运行时会出现无效的强制转换异常

但是这个技巧是有效的,因为像这样的方法永远不会被“调用”,而是被转换为SQL,SQLServerEFCoreProvider会删除这样的强制转换,并允许您使用SqlServer隐式数据转换。我在和中使用相同的技术(尽管方向相反)

下面是它如何映射到
表达式
方法。给定
Expression searchKeyExpression
(具体的
Expression
类型无关紧要),重要的是
Expression.type
属性返回的
type
。如果它是
string
,则可以,否则需要对其应用
(string)(object)
强制转换,这是通过两个
表达式.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编写的。您试图生成/模拟的确切SQL是什么?您确定SQL确实有效吗(即,您是否尝试在数据库上运行它)?它对字符串有效,对于EF函数扩展有两个字符串参数的方法。但是我想使用数字类型的功能。context.Set()。其中(e=>EF.Functions.Like((字符串)(对象)e.IntCol,“%1%”)。对于整型列,这将转换带有like的SQL语句。这是我在direct函数中找到的。我正在寻找与成员expression相同的内容。我已使用expression link更新了类似操作的逻辑。但同样的事情,我如何使用例如整数,十进制,bigint columnsit是有意义的,否则我不会在这里发布。对于那些没有理解我的问题就发表评论的人,请查看伊万·斯托夫的答案。如果你不理解这个问题,你可以忽略它。我发布这个问题是因为答案就在那个里,我被转换部分卡住了。他解释得很好,这是个绝妙的把戏。很高兴我不是唯一一个面对这种情况的人。实际上,我的睡眠时间差不多了。我会检查并让你知道答案。我被困在转换部分。但是你提到的一个问题Type.EmptyTypes我没有得到那部分,这是一个方便的
Expression.Call重载,用于“调用”静态方法。第三个参数是
Type[]
,表示方法的泛型类型参数。对于非泛型方法,我们只需传递空类型数组,确切的
类型.EmptyTypes
是什么:)当然,当传递正确的参数时,您的方式(使用另一个
调用
重载)也会起作用。我们在EF Core 2.2中使用了相同的修复,但现在在EF Core 3中不再起作用。*。异常消息为“对象引用未设置为对象的实例”。Stacktrace:at Microsoft.EntityFrameworkCore.Query.ExpressionExtensions.InferTypeMapping(SqlExpression[]表达式)at Microsoft.EntityFrameworkCore.Query.SqlExpressionFactory.ApplyTypeMappingOnLike(LikeExpression LikeExpression)在Microsoft.EntityFrameworkCore.Query.SqlExpressionFactory.ApplyTypeMapping(SqlExpression SqlExpression,RelationalTypeMapping typeMapping)中,将Microsoft.EntityFrameworkCore和Microsoft.EntityFrameworkCore.SqlServer更新为3.1.0修复了此问题