如何让LINQ表达式中的Contains搜索实现大小写不敏感?
问题:让Expression生成的Contains搜索支持大小写不敏感
我编写了一个用于创建Expression的方法处理搜索逻辑,代码如下:
private static Expression GenerateExpressionForString(Expression left, ItemComparisonOperator itemComparisonOperator, object value) { StringComparisonOperator stringOperator = Enum.Parse<StringComparisonOperator>(itemComparisonOperator.ToString()); ConstantExpression constant = Expression.Constant(value, left.Type); if (stringOperator is StringComparisonOperator.Equal or StringComparisonOperator.NotEqual) { ExpressionType nativeComparison = Enum.Parse<ExpressionType>(stringOperator.ToString()); return Expression.MakeBinary(nativeComparison, left, constant); } if (stringOperator is StringComparisonOperator.Contains) { return Expression.Call(left, stringOperator.ToString(), Type.EmptyTypes, constant); } if (stringOperator is StringComparisonOperator.StartsWith or StringComparisonOperator.EndsWith) return Expression.Call(left, stringOperator.ToString(), Type.EmptyTypes, constant); throw new NotSupportedException($"Invalid comparison operator '{itemComparisonOperator}'."); }
目前该方法除Contains搜索外均正常工作,但Contains搜索是大小写敏感模式,请问如何修改代码实现大小写不敏感?
解决方案
要实现大小写不敏感的Contains搜索,有两种常用方案,可根据你的场景选择:
方案1:调用带StringComparison参数的Contains重载
string.Contains提供了接受StringComparison枚举的重载,传入StringComparison.OrdinalIgnoreCase(或其他忽略大小写的枚举值)即可实现不敏感匹配。修改Contains分支代码如下:
if (stringOperator is StringComparisonOperator.Contains) { // 生成StringComparison.OrdinalIgnoreCase的常量表达式 var stringComparisonExpr = Expression.Constant(StringComparison.OrdinalIgnoreCase); // 调用string.Contains(string value, StringComparison comparisonType)重载 return Expression.Call( left, nameof(string.Contains), Type.EmptyTypes, constant, stringComparisonExpr ); }
注意:如果表达式最终要转换为EF Core等ORM查询,需确认ORM支持该重载的翻译(EF Core 3.0+已支持)。
方案2:统一转为小写/大写后比较
若场景不支持方案1(比如旧版ORM不识别带参数的Contains重载),可以将左表达式和常量值统一转为小写(或大写)后再调用Contains:
if (stringOperator is StringComparisonOperator.Contains) { // 左表达式转小写 var toLowerLeft = Expression.Call(left, nameof(string.ToLower), Type.EmptyTypes); // 常量值转小写(需确保value不为null,可提前加null检查) var lowerConstant = Expression.Constant(((string)value).ToLower(), left.Type); // 调用小写后的Contains方法 return Expression.Call(toLowerLeft, nameof(string.Contains), Type.EmptyTypes, lowerConstant); }
完整修改后的代码(以方案1为例)
private static Expression GenerateExpressionForString(Expression left, ItemComparisonOperator itemComparisonOperator, object value) { StringComparisonOperator stringOperator = Enum.Parse<StringComparisonOperator>(itemComparisonOperator.ToString()); ConstantExpression constant = Expression.Constant(value, left.Type); if (stringOperator is StringComparisonOperator.Equal or StringComparisonOperator.NotEqual) { ExpressionType nativeComparison = Enum.Parse<ExpressionType>(stringOperator.ToString()); return Expression.MakeBinary(nativeComparison, left, constant); } if (stringOperator is StringComparisonOperator.Contains) { var stringComparisonExpr = Expression.Constant(StringComparison.OrdinalIgnoreCase); return Expression.Call( left, nameof(string.Contains), Type.EmptyTypes, constant, stringComparisonExpr ); } if (stringOperator is StringComparisonOperator.StartsWith or StringComparisonOperator.EndsWith) { // 可选:给StartsWith/EndsWith也添加大小写不敏感支持 var stringComparisonExpr = Expression.Constant(StringComparison.OrdinalIgnoreCase); return Expression.Call( left, stringOperator.ToString(), Type.EmptyTypes, constant, stringComparisonExpr ); } throw new NotSupportedException($"Invalid comparison operator '{itemComparisonOperator}'."); }
内容的提问来源于stack exchange,提问作者Eugene Sukh
相关产品推荐
相关产品推荐

