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

时间:2019-06-22 11:29:21

标签: 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, Expression.Constant($"%{filter.Value}%"));

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

  

自变量示例:System.Int32表达式中的自变量异常不能用于方法类型为Boolean Like(Ef.DBfuntions)的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 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 Core版本:(ASP.NET Core 2.1) 数据库提供程序:(例如Microsoft.EntityFrameworkCore.SqlServer) 操作系统: IDE :(例如Visual Studio 2017 15.4)

1 个答案:

答案 0 :(得分:3)

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

但是该技巧之所以有效,是因为此类方法从未被“调用”,而是转换为SQL,并且SqlServer EF Core提供程序删除了此类强制类型转换,并允许您使用SqlServer隐式数据转换。我在How can a JSON_VALUE be converted to a DateTime with EF Core 2.2?Expression tree to SQL with EF Core中使用了相同的技术(尽管方向相反)。

这是映射到Expression方法的方式。给定Expression searchKeyExpression(具体的Expression类型无关紧要),重要的是Type属性返回的Expression.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);