6

我基本上是在尝试构建一个查询,我不知道为什么微软在 Entity Framework 和 LINQ 中让这变得如此困难。我有各种参数字符串。因此,如果您看到一个变量,假设它是从某个地方传入的字符串。

             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();

我的问题是在 LINQ 的“Where()”函数中放什么。

我想用字符串“searchfield”搜索一个字段,其值为 .contains()“search”。

不知道为什么 Visual Studio 不会让我轻松做到这一点。

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

.Where(x => x.GetType().GetProperty(searchfield).GetValue(x, null).ToList().Contains(search))

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

4

4 回答 4

9

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

在某处创建一个辅助方法

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);
}

像这样使用它

users = this.entities.tableUsers
                     .Where(GetContainsExpression<User>(searchfield, search))
                     .OrderBy(GetPropertyExpression<User, string>(searchfield))
                     ...

更新

作为替代方案,您可以创建扩展方法以提供更简洁的语法。在某处的静态类中创建以下方法:

    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>;
    }

然后你可以这样称呼他们:

var users = this.entities.tableUsers.WhereStringContains(searchField, search)
                                    .OrderBy(searchField);
于 2012-08-16T20:01:13.487 回答
5

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

不,如果它违背了这种语言范式,它不应该。LINQ 和实体框架(以及任何其他体面的 ORM)正是为了避免您想要完成的事情而制作的:非类型化和非编译器可验证的查询。所以基本上你是在迫使方钉进入圆孔。

您仍然可以查看Dynamic LINQ

于 2012-08-16T19:43:54.330 回答
2

您必须构建一个表达式树才能传递给该Where方法。这是我撒谎的一些代码的松散改编:

string searchfield, value; // Your inputs
var param = Expression.Parameter(typeof(User), "user");

return Expression.Lambda<Func<T, bool>>(
    Expression.Call(
        Expression.Property(
            param,
            typeof(User).GetProperty(searchfield)),
        typeof(string).GetMethod("Contains"),
        Expression.Constant(value)),
    param);

这将生成一个适当的表达式以用作Where.

编辑:仅供参考,结果表达式将类似于user => user.Foo.Contains(bar).

编辑:要排序,像这样(从我的 DynamicOrderList 类中提取):

private IQueryable<T> OrderQuery<T>(IQueryable<T> query, OrderParameter orderBy)
{
    string orderMethodName = orderBy.Direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
    Type t = typeof(T);

    var param = Expression.Parameter(t, "user");
    var property = t.GetProperty(orderBy.Attribute);

    return query.Provider.CreateQuery<T>(
        Expression.Call(
            typeof(Queryable),
            orderMethodName,
            new Type[] { t, typeof(string) },
            query.Expression,
            Expression.Quote(
                Expression.Lambda(
                    Expression.Property(param, property),
                    param))
        ));
}
于 2012-08-16T19:51:37.527 回答
0

我对您关于此的其他问题的回答:

在实体框架中创建动态 linq 排序和搜索顺序语句时

于 2012-08-16T19:46:46.187 回答