Home > OS >  How to search based on contains using DynamicFilterBuilder in C#
How to search based on contains using DynamicFilterBuilder in C#

Time:10-23

In my project currently i have implemented multiple searching using below function code:

public static IQueryable<T> Filter<T>(this IQueryable<T> source, SearchCriteria searchCriteria)
    {
        var predicate = new DynamicFilterBuilder<T>();

        foreach (var item in searchCriteria.filters)
        {

            if (!string.IsNullOrEmpty(item.key))
            {
                if (item.key == "CreatedOn")
                    predicate.And(item.key, DynamicExpressions.FilterOperator.GreaterThanOrEqual, DateTime.ParseExact(item.value.ToString()   " 00:00:00", "yyyy-MM-dd HH:mm:ss", null))
                    .And(item.key, DynamicExpressions.FilterOperator.LessThanOrEqual, DateTime.ParseExact(item.value.ToString()   " 23:59:59", "yyyy-MM-dd HH:mm:ss", null));
                else
                    predicate.And(item.key,
                      DynamicExpressions.FilterOperator.Contains, item.value);
            }
        }

        return source.Where(predicate.Build());
    }

But it's working only like Case sensitive means i need to pass exactly Name ex : "Data" if i passed "data" it's not returning anything so can someone help me on this ?

CodePudding user response:

You can do a lower case conversion here and compare with a lowercase like below:

  if (item.key.ToLower() == "createdon")
    {
         //Your stuff
    }

CodePudding user response:

The package from zHaytam mentioned in the comment ( github.com/zHaytam/DynamicExpressions) is open source on GitHub so we can see that in its implementation (Class DynamicExpressions), the expressions are delegating to Linq expressions:

private static Expression CreateFilter(MemberExpression prop, FilterOperator op, ConstantExpression constant)
        {
            return op switch
            {
                FilterOperator.Equals => Expression.Equal(prop, constant),
                FilterOperator.GreaterThan => Expression.GreaterThan(prop, constant),
                FilterOperator.LessThan => Expression.LessThan(prop, constant),
                FilterOperator.Contains => Expression.Call(prop, _containsMethod, PrepareConstant(constant)),
                FilterOperator.StartsWith => Expression.Call(prop, _startsWithMethod, PrepareConstant(constant)),
                FilterOperator.EndsWith => Expression.Call(prop, _endsWithMethod, PrepareConstant(constant)),
                FilterOperator.DoesntEqual => Expression.NotEqual(prop, constant),
                FilterOperator.GreaterThanOrEqual => Expression.GreaterThanOrEqual(prop, constant),
                FilterOperator.LessThanOrEqual => Expression.LessThanOrEqual(prop, constant),
                _ => throw new NotImplementedException()
            };
        }

and the containsMethod uses the version public bool Contains (string value); of string.Contains:

        private static readonly MethodInfo _containsMethod = typeof(string).GetMethod("Contains"
            , new Type[] { typeof(string) });

To make the "Contains" method become case-insensitive, I think you can download and modify zHaytam's code:

In method DynamicExpressions modify the initialization expression of _containsMethod to reference the public bool Contains (string value, StringComparison comparisonType) version of string.Contains:

        private static readonly MethodInfo _containsMethod = typeof(string).GetMethod("Contains"
            , new Type[] { typeof(string), typeof(StringComparison) });

and modify the CreateFilter method to provide the additional parameter to ignore case:

FilterOperator.Contains => Expression.Call(prop, _containsMethod, PrepareConstant(constant), Expression.Constant(StringComparison.OrdinalIgnoreCase)),
  • Related