How to construct a dynamic where filter in EF.Core to handle equals, LIKE, gt, lt, etc

后端 未结 3 1205
醉梦人生
醉梦人生 2020-12-30 14:54

Please how do we construct a dynamic where filter in EF.Core to handle:

Query.Where(fieldName, compareMode, value)

I basically Expect to us

3条回答
  •  再見小時候
    2020-12-30 15:14

    I modified the answer I found here: Linq WHERE EF.Functions.Like - Why direct properties work and reflection does not?

    I chucked together a version for those using NpgSQL as their EF Core provider as you will need to use the ILike function instead if you want case-insensitivity, also added a second version which combines a bunch of properties into a single Where() clause:

    public static IQueryable WhereLike(this IQueryable source, string propertyName, string searchTerm)
        {
            // Check property name
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException(nameof(propertyName));
            }
    
            // Check the search term
            if(string.IsNullOrEmpty(searchTerm))
            {
                throw new ArgumentNullException(nameof(searchTerm));
            }
    
            // Check the property exists
            var property = typeof(T).GetProperty(propertyName);
            if (property == null)
            {
                throw new ArgumentException($"The property {typeof(T)}.{propertyName} was not found.", nameof(propertyName));
            }
    
            // Check the property type
            if(property.PropertyType != typeof(string))
            {
                throw new ArgumentException($"The specified property must be of type {typeof(string)}.", nameof(propertyName));
            }
    
            // Get expression constants
            var searchPattern = "%" + searchTerm + "%";
            var itemParameter = Expression.Parameter(typeof(T), "item");
            var functions = Expression.Property(null, typeof(EF).GetProperty(nameof(EF.Functions)));
            var likeFunction = typeof(NpgsqlDbFunctionsExtensions).GetMethod(nameof(NpgsqlDbFunctionsExtensions.ILike), new Type[] { functions.Type, typeof(string), typeof(string) });
    
            // Build the property expression and return it
            Expression selectorExpression = Expression.Property(itemParameter, property.Name);
            selectorExpression = Expression.Call(null, likeFunction, functions, selectorExpression, Expression.Constant(searchPattern));
            return source.Where(Expression.Lambda>(selectorExpression, itemParameter));
        }
    
        public static IQueryable WhereLike(this IQueryable source, IEnumerable propertyNames, string searchTerm)
        {
            // Check property name
            if (!(propertyNames?.Any() ?? false))
            {
                throw new ArgumentNullException(nameof(propertyNames));
            }
    
            // Check the search term
            if (string.IsNullOrEmpty(searchTerm))
            {
                throw new ArgumentNullException(nameof(searchTerm));
            }
    
            // Check the property exists
            var properties = propertyNames.Select(p => typeof(T).GetProperty(p)).AsEnumerable();
            if (properties.Any(p => p == null))
            {
                throw new ArgumentException($"One or more specified properties was not found on type {typeof(T)}: {string.Join(",", properties.Where(p => p == null).Select((p, i) => propertyNames.ElementAt(i)))}.", nameof(propertyNames));
            }
    
            // Check the property type
            if (properties.Any(p => p.PropertyType != typeof(string)))
            {
                throw new ArgumentException($"The specified properties must be of type {typeof(string)}: {string.Join(",", properties.Where(p => p.PropertyType != typeof(string)).Select(p => p.Name))}.", nameof(propertyNames));
            }
    
            // Get the expression constants
            var searchPattern = "%" + searchTerm + "%";
            var itemParameter = Expression.Parameter(typeof(T), "item");
            var functions = Expression.Property(null, typeof(EF).GetProperty(nameof(EF.Functions)));
            var likeFunction = typeof(NpgsqlDbFunctionsExtensions).GetMethod(nameof(NpgsqlDbFunctionsExtensions.ILike), new Type[] { functions.Type, typeof(string), typeof(string) });
    
            // Build the expression and return it
            Expression selectorExpression = null;
            foreach (var property in properties)
            {
                var previousSelectorExpression = selectorExpression;
                selectorExpression = Expression.Property(itemParameter, property.Name);
                selectorExpression = Expression.Call(null, likeFunction, functions, selectorExpression, Expression.Constant(searchPattern));
                if(previousSelectorExpression != null)
                {
                    selectorExpression = Expression.Or(previousSelectorExpression, selectorExpression);
                }
            }
            return source.Where(Expression.Lambda>(selectorExpression, itemParameter));
        }
    

提交回复
热议问题