Search through Where clause in LINQ, using dynamic properties

前端 未结 4 1157
长情又很酷
长情又很酷 2021-01-12 17:58

I\'m basically trying to construct a query, and I don\'t know why microsoft made this so difficult in Entity Framework and LINQ. I have various parameter STRINGS. So if you

4条回答
  •  时光说笑
    2021-01-12 18:53

    This is not trivial, but I believe it can be done. The following has not been tested. The code is borrowed from here.

    Create a helper method somewhere like

    public static Expression> GetContainsExpression(string propertyName, string containsValue)
    {
        var parameterExp = Expression.Parameter(typeof(T), "type");
        var propertyExp = Expression.Property(parameterExp, propertyName);
        MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var someValue = Expression.Constant(propertyValue, typeof(string));
        var containsMethodExp = Expression.Call(propertyExp, method, someValue);
    
        return Expression.Lambda>(containsMethodExp, parameterExp);
    }
    
    public static Expression> GetPropertyExpression(string propertyName)
    {
        var parameterExp = Expression.Parameter(typeof(T), "type");
        var exp = Expression.Property(parameterExp, propertyName);
        return Expression.Lambda>(exp, parameterExp);
    }
    

    Use it like

    users = this.entities.tableUsers
                         .Where(GetContainsExpression(searchfield, search))
                         .OrderBy(GetPropertyExpression(searchfield))
                         ...
    

    UPDATE

    As an alternative, you could create extension methods to provide a cleaner syntax. Create the following methods in a static class somewhere:

        public static IQueryable WhereStringContains(this IQueryable query, string propertyName, string contains)
        {
            var parameter = Expression.Parameter(typeof(T), "type");
            var propertyExpression = Expression.Property(parameter, propertyName);
            MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            var someValue = Expression.Constant(contains, typeof(string));
            var containsExpression = Expression.Call(propertyExpression, method, someValue);
    
            return query.Where(Expression.Lambda>(containsExpression, parameter));
        }
    
        public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName)
        {
            var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
            var parameter = Expression.Parameter(typeof(T), "type");
            var propertyExpression = Expression.Property(parameter, propertyName);
            var lambda = Expression.Lambda(propertyExpression, new[] { parameter });
    
            return typeof(Queryable).GetMethods()
                                    .Where(m => m.Name == "OrderBy" && m.GetParameters().Length == 2)
                                    .Single()
                                    .MakeGenericMethod(new[] { typeof(T), propertyType })
                                    .Invoke(null, new object[] { query, lambda }) as IOrderedQueryable;
        }
    
        public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName)
        {
            var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
            var parameter = Expression.Parameter(typeof(T), "type");
            var propertyExpression = Expression.Property(parameter, propertyName);
            var lambda = Expression.Lambda(propertyExpression, new[] { parameter });
    
            return typeof(Queryable).GetMethods()
                                    .Where(m => m.Name == "OrderByDescending" && m.GetParameters().Length == 2)
                                    .Single()
                                    .MakeGenericMethod(new[] { typeof(T), propertyType })
                                    .Invoke(null, new object[] { query, lambda }) as IOrderedQueryable;
        }
    

    Then you can call them like:

    var users = this.entities.tableUsers.WhereStringContains(searchField, search)
                                        .OrderBy(searchField);
    

提交回复
热议问题