diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 18c20cc24fa..4f7144f245e 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.2.0 + 10.2.1-beta01 diff --git a/src/BootstrapBlazor/Extensions/LambdaExtensions.cs b/src/BootstrapBlazor/Extensions/LambdaExtensions.cs index ec7cd250343..9433ffe8367 100644 --- a/src/BootstrapBlazor/Extensions/LambdaExtensions.cs +++ b/src/BootstrapBlazor/Extensions/LambdaExtensions.cs @@ -34,27 +34,27 @@ private class ComboExpressionVisitor(ParameterExpression parameter) : Expression /// /// /// - /// - public static Func GetFilterFunc(this FilterKeyValueAction filter) => filter.GetFilterLambda().Compile(); + /// 实例,此方法不支持 EFCore Where 查询 + public static Func GetFilterFunc(this FilterKeyValueAction filter, StringComparison? comparison = null) => filter.GetFilterLambda(comparison).Compile(); /// /// 指定 FilterKeyValueAction 获取 Lambda 表达式 /// /// /// - /// - public static Expression> GetFilterLambda(this FilterKeyValueAction filter) + /// 实例,此方法不支持 EFCore Where 查询 + public static Expression> GetFilterLambda(this FilterKeyValueAction filter, StringComparison? comparison = null) { var express = new List>>(); if (filter.Filters.Count > 0) { express.AddRange(filter.Filters.Select(f => f.Filters.Count > 0 - ? f.Filters.GetFilterLambda(f.FilterLogic) - : f.GetInnerFilterLambda())); + ? f.Filters.GetFilterLambda(f.FilterLogic, comparison) + : f.GetInnerFilterLambda(comparison))); } else { - express.Add(filter.GetInnerFilterLambda()); + express.Add(filter.GetInnerFilterLambda(comparison)); } return express.ExpressionAndLambda(filter.FilterLogic); } @@ -83,12 +83,13 @@ public static Expression> GetFilterLambda(this FilterKe /// /// /// + /// 实例 /// - private static Expression> GetFilterLambda(this IEnumerable filters, FilterLogic logic) + private static Expression> GetFilterLambda(this IEnumerable filters, FilterLogic logic, StringComparison? comparison = null) { var express = filters.Select(filter => filter.Filters.Count > 0 - ? filter.Filters.GetFilterLambda(filter.FilterLogic) - : filter.GetInnerFilterLambda()) + ? filter.Filters.GetFilterLambda(filter.FilterLogic, comparison) + : filter.GetInnerFilterLambda(comparison)) .ToList(); return express.ExpressionAndLambda(logic); } @@ -126,13 +127,7 @@ private static Expression> ExpressionAndLambda(this IEn return ret ?? (r => true); } - /// - /// 指定 FilterKeyValueAction 获取 Lambda 表达式 - /// - /// - /// - /// - private static Expression> GetInnerFilterLambda(this FilterKeyValueAction filter) + private static Expression> GetInnerFilterLambda(this FilterKeyValueAction filter, StringComparison? comparison = null) { Expression> ret = t => true; var type = typeof(TItem); @@ -148,7 +143,7 @@ Expression> GetSimpleFilterExpression() var prop = typeof(TItem).GetPropertyByName(filter.FieldKey) ?? throw new InvalidOperationException($"the model {type.Name} not found the property {filter.FieldKey}"); var parameter = Expression.Parameter(type); var fieldExpression = Expression.Property(parameter, prop); - ret = filter.GetFilterExpression(prop, fieldExpression, parameter); + ret = filter.GetFilterExpression(prop, fieldExpression, parameter, comparison); return ret; } @@ -175,13 +170,13 @@ Expression> GetComplexFilterExpression() if (fieldExpression != null) { - ret = filter.GetFilterExpression(prop, fieldExpression, parameter); + ret = filter.GetFilterExpression(prop, fieldExpression, parameter, comparison); } return ret; } } - private static Expression> GetFilterExpression(this FilterKeyValueAction filter, PropertyInfo? prop, Expression fieldExpression, ParameterExpression parameter) + private static Expression> GetFilterExpression(this FilterKeyValueAction filter, PropertyInfo? prop, Expression fieldExpression, ParameterExpression parameter, StringComparison? comparison = null) { var isNullable = false; var eq = fieldExpression; @@ -201,12 +196,12 @@ private static Expression> GetFilterExpression(this Fil } } eq = isNullable - ? Expression.AndAlso(Expression.NotEqual(fieldExpression, Expression.Constant(null)), filter.GetExpression(eq)) - : filter.GetExpression(eq); + ? Expression.AndAlso(Expression.NotEqual(fieldExpression, Expression.Constant(null)), filter.GetExpression(eq, comparison)) + : filter.GetExpression(eq, comparison); return Expression.Lambda>(eq, parameter); } - private static Expression GetExpression(this FilterKeyValueAction filter, Expression left) + private static Expression GetExpression(this FilterKeyValueAction filter, Expression left, StringComparison? comparison = null) { var right = Expression.Constant(filter.FieldValue); return filter.FilterAction switch @@ -217,8 +212,8 @@ private static Expression GetExpression(this FilterKeyValueAction filter, Expres FilterAction.GreaterThanOrEqual => Expression.GreaterThanOrEqual(left, right), FilterAction.LessThan => Expression.LessThan(left, right), FilterAction.LessThanOrEqual => Expression.LessThanOrEqual(left, right), - FilterAction.Contains => left.Contains(right), - FilterAction.NotContains => Expression.Not(left.Contains(right)), + FilterAction.Contains => left.Contains(right, comparison), + FilterAction.NotContains => Expression.Not(left.Contains(right, comparison)), _ => filter.FieldValue switch { LambdaExpression t => Expression.Invoke(t, left), @@ -228,12 +223,23 @@ private static Expression GetExpression(this FilterKeyValueAction filter, Expres }; } - private static BinaryExpression Contains(this Expression left, Expression right) + private static BinaryExpression Contains(this Expression left, Expression right, StringComparison? comparison) => comparison.HasValue + ? ContainsWidthComparison(left, right, comparison.Value) + : ContainsWithoutComparison(left, right); + + private static BinaryExpression ContainsWithoutComparison(this Expression left, Expression right) { var method = typeof(string).GetMethod("Contains", [typeof(string)])!; return Expression.AndAlso(Expression.NotEqual(left, Expression.Constant(null)), Expression.Call(left, method, right)); } + private static BinaryExpression ContainsWidthComparison(this Expression left, Expression right, StringComparison comparison) + { + var method = typeof(string).GetMethod("Contains", [typeof(string), typeof(StringComparison)])!; + var comparisonConstant = Expression.Constant(comparison); + return Expression.AndAlso(Expression.NotEqual(left, Expression.Constant(null)), Expression.Call(left, method, right, comparisonConstant)); + } + #region Count /// /// Count 方法内部使用 Lambda 表达式做通用适配 可接受 IEnumerable 与 Array 子类 diff --git a/src/BootstrapBlazor/Extensions/QueryPageOptionsExtensions.cs b/src/BootstrapBlazor/Extensions/QueryPageOptionsExtensions.cs index cf3c52ce585..da3346c2fbc 100644 --- a/src/BootstrapBlazor/Extensions/QueryPageOptionsExtensions.cs +++ b/src/BootstrapBlazor/Extensions/QueryPageOptionsExtensions.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone @@ -56,15 +56,17 @@ public static FilterKeyValueAction ToFilter(this QueryPageOptions option) /// 将 QueryPageOptions 过滤条件转换为 where 条件中的参数 "/> 推荐 Linq 使用 /// /// + /// 实例,此方法不支持 EFCore Where 查询 /// - public static Func ToFilterFunc(this QueryPageOptions option) => option.ToFilterLambda().Compile(); + public static Func ToFilterFunc(this QueryPageOptions option, StringComparison? comparison = null) => option.ToFilterLambda(comparison).Compile(); /// /// 将 QueryPageOptions 过滤条件转换为 表达式"/> 推荐 EFCore 使用 /// /// + /// 实例,此方法不支持 EFCore Where 查询 /// - public static Expression> ToFilterLambda(this QueryPageOptions option) => option.ToFilter().GetFilterLambda(); + public static Expression> ToFilterLambda(this QueryPageOptions option, StringComparison? comparison = null) => option.ToFilter().GetFilterLambda(comparison); /// /// 是否包含过滤条件 diff --git a/test/UnitTest/Extensions/LambadaExtensionsTest.cs b/test/UnitTest/Extensions/LambadaExtensionsTest.cs index e755a68b68e..e326c618d34 100644 --- a/test/UnitTest/Extensions/LambadaExtensionsTest.cs +++ b/test/UnitTest/Extensions/LambadaExtensionsTest.cs @@ -12,6 +12,30 @@ namespace UnitTest.Extensions; public class LambadaExtensionsTest : BootstrapBlazorTestBase { + [Fact] + public void GetFilterFunc_Comparison() + { + var filter = new FilterKeyValueAction() + { + FieldKey = "Name", + FilterAction = FilterAction.Contains, + FieldValue = "T" + }; + + var foos = new Foo[] + { + new() { Name = "Test1" }, + new() { Name = "test2" }, + }; + + var items = foos.Where(filter.GetFilterFunc()); + Assert.Single(items); + + // 忽略大小写 + items = foos.Where(filter.GetFilterFunc(StringComparison.OrdinalIgnoreCase)); + Assert.Equal(2, items.Count()); + } + [Fact] public void GetFilterFunc_Null() { @@ -694,11 +718,6 @@ public override FilterKeyValueAction GetFilterConditions() } } - /// - /// - /// - /// - /// private class CustomDynamicData(Dictionary data) : System.Dynamic.DynamicObject { /// @@ -719,9 +738,9 @@ public CustomDynamicData() : this([]) { } /// public override bool TryGetMember(GetMemberBinder binder, out object? result) { - if (Dynamic.ContainsKey(binder.Name)) + if (Dynamic.TryGetValue(binder.Name, out string? value)) { - result = Dynamic[binder.Name]; + result = value; } else { diff --git a/test/UnitTest/Extensions/QueryPageOptionsExtensionsTest.cs b/test/UnitTest/Extensions/QueryPageOptionsExtensionsTest.cs index 6cec1d3537f..7f8ac62c93a 100644 --- a/test/UnitTest/Extensions/QueryPageOptionsExtensionsTest.cs +++ b/test/UnitTest/Extensions/QueryPageOptionsExtensionsTest.cs @@ -39,6 +39,11 @@ public void ToFilter_Searches() expected = _foos.Where(predicate); Assert.Equal(2, expected.Count()); + // 忽略大小写 + predicate = option.ToFilterFunc(StringComparison.OrdinalIgnoreCase); + expected = _foos.Where(predicate); + Assert.Equal(4, expected.Count()); + option.Searches.Clear(); option.Searches.Add(new SearchFilterAction("Name", "Mock")); predicate = option.ToFilterFunc();