.NET 核心 Npgsql.EntityFrameworkCore ILikeExpression
.NET Core Npgsql.EntityFrameworkCore ILikeExpression
我正在使用 EntityFramework Core 和 Npgsql 提供程序,执行 ILIKE 查询工作正常:
var query = dbContext.countries
.Where(w => (w.name != null &&
EF.Functions.ILike(w.name, $"{search}%")
);
查询已转换为 PostgreSQL 的 ILIKE,目前一切顺利。
我还在构建基于注释的动态 LINQ - 模型中的 [Searchable] 或 [Orderable] 属性 - 我正在尝试找出如何使用表达式和 Lambda 执行 ILIKE。代码:
// works, except it produces just LIKE which is case sensitive. Not enough.
expr = Expression.Call(property, nameof(string.Contains), new Type[] { }, Expression.Constant(search));
// does not work, ends with exception, see below
expr = new Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal.ILikeExpression(property, Expression.Constant(search_query));
有什么想法吗?谢谢!
// Exception
Application started. Press Ctrl+C to shut down.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLGC19DMS3OI", Request id "0HLGC19DMS3OI:00000001": An unhandled exception was thrown by the application.
System.ArgumentException: must be reducible node
at System.Linq.Expressions.Expression.ReduceAndCheck()
at System.Linq.Expressions.Expression.ReduceExtensions()
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExtensionExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateExecutorLambda[TResults]()
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken
cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
解决方法:
var _regex = typeof(System.Text.RegularExpressions.Regex).GetMethod("IsMatch",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(string),
typeof(string),
typeof(System.Text.RegularExpressions.RegexOptions)
},
null
);
_expr = Expression.Call(_regex, property, Expression.Constant(search, typeof(string)), Expression.Constant(System.Text.RegularExpressions.RegexOptions.IgnoreCase));
编辑
工作代码:
var _ILike = typeof(NpgsqlDbFunctionsExtensions).GetMethod("ILike",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(Microsoft.EntityFrameworkCore.DbFunctions),
typeof(string),
typeof(string)
},
null
);
_expr = Expression.Call(
_ILike,
Expression.Constant(null, typeof(DbFunctions)),
property,
Expression.Constant(search, typeof(string)));
您需要发出与 EF.Functions.ILike(string, string)
调用等效的表达式。
ILike
是定义为
的静态扩展方法
public static class NpgsqlDbFunctionsExtensions
{
public static bool ILike(this DbFunctions _, string matchExpression, string pattern);
}
和Functions
是静态属性的EF
class
public static class EF
{
public static DbFunctions Functions { get; }
}
因此您要查找的表达式是这样的:
expr = Expression.Call(
typeof(NpgsqlDbFunctionsExtensions),
nameof(NpgsqlDbFunctionsExtensions.ILike),
Type.EmptyTypes,
Expression.Property(null, typeof(EF), nameof(EF.Functions)),
property,
Expression.Constant(search)
);
这(其中 T class)有效:
public static Expression<Func<T, bool>> GetCriteriaWhere<T>(string fieldName, object fieldValue)
{
PropertyInfo prop = typeof(T).GetProperty(fieldName);
var parameter = Expression.Parameter(typeof(T));
var expressionParameter = GetMemberExpression<T>(parameter, fieldName);
var _ILike = typeof(NpgsqlDbFunctionsExtensions).GetMethod("ILike",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(Microsoft.EntityFrameworkCore.DbFunctions),
typeof(string),
typeof(string)
},
null
);
var bodyLike = Expression.Call(_ILike, Expression.Constant(null, typeof(DbFunctions)), expressionParameter, Expression.Constant("%" + fieldValue + "%", typeof(string)));
return Expression.Lambda<Func<T, bool>>(bodyLike, parameter);
}
我正在使用 EntityFramework Core 和 Npgsql 提供程序,执行 ILIKE 查询工作正常:
var query = dbContext.countries
.Where(w => (w.name != null &&
EF.Functions.ILike(w.name, $"{search}%")
);
查询已转换为 PostgreSQL 的 ILIKE,目前一切顺利。
我还在构建基于注释的动态 LINQ - 模型中的 [Searchable] 或 [Orderable] 属性 - 我正在尝试找出如何使用表达式和 Lambda 执行 ILIKE。代码:
// works, except it produces just LIKE which is case sensitive. Not enough.
expr = Expression.Call(property, nameof(string.Contains), new Type[] { }, Expression.Constant(search));
// does not work, ends with exception, see below
expr = new Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal.ILikeExpression(property, Expression.Constant(search_query));
有什么想法吗?谢谢!
// Exception
Application started. Press Ctrl+C to shut down.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLGC19DMS3OI", Request id "0HLGC19DMS3OI:00000001": An unhandled exception was thrown by the application.
System.ArgumentException: must be reducible node
at System.Linq.Expressions.Expression.ReduceAndCheck()
at System.Linq.Expressions.Expression.ReduceExtensions()
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExtensionExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLogicalBinaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateExecutorLambda[TResults]()
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken
cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
解决方法:
var _regex = typeof(System.Text.RegularExpressions.Regex).GetMethod("IsMatch",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(string),
typeof(string),
typeof(System.Text.RegularExpressions.RegexOptions)
},
null
);
_expr = Expression.Call(_regex, property, Expression.Constant(search, typeof(string)), Expression.Constant(System.Text.RegularExpressions.RegexOptions.IgnoreCase));
编辑
工作代码:
var _ILike = typeof(NpgsqlDbFunctionsExtensions).GetMethod("ILike",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(Microsoft.EntityFrameworkCore.DbFunctions),
typeof(string),
typeof(string)
},
null
);
_expr = Expression.Call(
_ILike,
Expression.Constant(null, typeof(DbFunctions)),
property,
Expression.Constant(search, typeof(string)));
您需要发出与 EF.Functions.ILike(string, string)
调用等效的表达式。
ILike
是定义为
public static class NpgsqlDbFunctionsExtensions
{
public static bool ILike(this DbFunctions _, string matchExpression, string pattern);
}
和Functions
是静态属性的EF
class
public static class EF
{
public static DbFunctions Functions { get; }
}
因此您要查找的表达式是这样的:
expr = Expression.Call(
typeof(NpgsqlDbFunctionsExtensions),
nameof(NpgsqlDbFunctionsExtensions.ILike),
Type.EmptyTypes,
Expression.Property(null, typeof(EF), nameof(EF.Functions)),
property,
Expression.Constant(search)
);
这(其中 T class)有效:
public static Expression<Func<T, bool>> GetCriteriaWhere<T>(string fieldName, object fieldValue)
{
PropertyInfo prop = typeof(T).GetProperty(fieldName);
var parameter = Expression.Parameter(typeof(T));
var expressionParameter = GetMemberExpression<T>(parameter, fieldName);
var _ILike = typeof(NpgsqlDbFunctionsExtensions).GetMethod("ILike",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] {
typeof(Microsoft.EntityFrameworkCore.DbFunctions),
typeof(string),
typeof(string)
},
null
);
var bodyLike = Expression.Call(_ILike, Expression.Constant(null, typeof(DbFunctions)), expressionParameter, Expression.Constant("%" + fieldValue + "%", typeof(string)));
return Expression.Lambda<Func<T, bool>>(bodyLike, parameter);
}