使用动态属性在LINQ中搜索Where子句

Dex*_*ter 6 c# linq asp.net linq-to-entities entity-framework

我基本上是在尝试构建一个查询,我不知道为什么microsoft在Entity Framework和LINQ中这么难.我有各种参数STRINGS.所以如果你看到一个变量,假设它是从某个地方传入的字符串.

             users = this.entities.tableUsers
                .Where(searchfield+" LIKE %@0%", search)
                .OrderBy(x => x.GetType().GetProperty(order_by).GetValue(x, null).ToString())
                .Skip(Convert.ToInt32(limit_begin))
                .Take(Convert.ToInt32(limit_end))
                .ToList();
Run Code Online (Sandbox Code Playgroud)

我的问题是在LINQ中放入"Where()"函数的内容.

我想搜索字符串"searchfield"的字段,值为.contains()"search".

不确定为什么Visual Studio不会让我轻易做到这一点.

我也试过这个,没有运气:

.Where(x => x.GetType().GetProperty(searchfield).GetValue(x, null).ToList().Contains(search))
Run Code Online (Sandbox Code Playgroud)

注意:我不想安装任何新库,这对于现代语言来说应该非常容易和简单.我不介意查询是否返回所有行,我用.Contains()搜索它.

小智 8

这不是微不足道的,但我相信它可以做到.以下未经过测试.代码是从这里借来的.

在某个地方创建一个帮助方法

public static Expression<Func<T, bool>> GetContainsExpression<T>(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<Func<T, bool>>(containsMethodExp, parameterExp);
}

public static Expression<Func<T, TKey>> GetPropertyExpression<T, TKey>(string propertyName)
{
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var exp = Expression.Property(parameterExp, propertyName);
    return Expression.Lambda<Func<T, TKey>>(exp, parameterExp);
}
Run Code Online (Sandbox Code Playgroud)

像它一样使用它

users = this.entities.tableUsers
                     .Where(GetContainsExpression<User>(searchfield, search))
                     .OrderBy(GetPropertyExpression<User, string>(searchfield))
                     ...
Run Code Online (Sandbox Code Playgroud)

UPDATE

作为替代方法,您可以创建扩展方法以提供更清晰的语法.在某个静态类中创建以下方法:

    public static IQueryable<T> WhereStringContains<T>(this IQueryable<T> 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<Func<T, bool>>(containsExpression, parameter));
    }

    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> 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<T>;
    }

    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> 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<T>;
    }
Run Code Online (Sandbox Code Playgroud)

然后你可以称他们为:

var users = this.entities.tableUsers.WhereStringContains(searchField, search)
                                    .OrderBy(searchField);
Run Code Online (Sandbox Code Playgroud)


Ser*_*sev 5

对于现代语言来说,这应该是非常容易和简单的

不,如果它违背了那种语言范式,那就不应该.LINQ和实体框架(以及任何其他体面的ORM)正是为了避免您要完成的任务而做出的:非类型化和非编译器可验证的查询.所以基本上你强迫方形钉进入圆孔.

您仍然可以查看Dynamic LINQ.