3

我正在尝试构建一个函数来根据某些参数动态生成不同的查询。我对 LINQ 语法有点困惑,我不确定我是否做得对。

字符串类型参数集是“search”(搜索文本框值)、“searchfield”(搜索内容)、“limit_begin”、“limit_end”,表示行数和从哪里开始。“order_by”按哪个字段排序。“order_sort”用于排序的方式。

我之前在stackoverflow上发现了这个'getpropertyvalue'反射函数,我希望它可以根据我自己的解释来做我想要的。

 private static object GetPropertyValue(object obj, string property)
    {
        System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
        return propertyInfo.GetValue(obj, null);
    }

if (order_sort == "ASC")
        {
            (from a in entities.UserTable
             where GetPropertyValue(a, searchfield).ToString().Contains(search)
             select a)
                .OrderBy("a." + order_by)
                .Skip(Convert.ToInt32(limit_begin))
                .Take(Convert.ToInt32(limit_end))
                .ToList();
        }
        else if (order_sort == "DESC")
        {
            (from a in entities.UserTable
             where GetPropertyValue(a, searchfield).ToString().Contains(search)
             select a)
                .OrderByDescending("a." + order_by)
                .Skip(Convert.ToInt32(limit_begin))
                .Take(Convert.ToInt32(limit_end))
                .ToList();
        }

我在“Orderby”行出现错误, VS2008 用红色突出显示它,表示无法从用法中推断出参数的类型。

4

3 回答 3

5

.OrderByand.OrderByDescending方法需要一个类型的参数,并且Func<T, TKey>您正在传递一个字符串。基本上,它要求您提供一个表达式,它可以用来识别您想要排序的属性。因为你必须从一个字符串开始,我最好的想法是在你的 OrderBy 中使用反射。

.OrderBy(x => x.GetType().GetProperty(order_by).GetValue(x, null).ToString())

如您所见,这不是很容易阅读,但应该可以解决问题。您还可以在以下位置查看 LINQ 动态查询库:http ://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-库.aspx

希望这可以帮助!:)

于 2012-08-16T18:03:36.430 回答
2

这就是我过去处理这个问题的方式。注意是单列搜索和排序,听起来像你想要的。

var users = entities.UserTable;

// Setup the default order column.
Func<SweetEntity, string> orderFunc = u => u.Field1;

switch (searchfield)
{
    case "Field1":
        orderFunc = u => u.Field1;
        users = users.Where(u => u.Field1.Contains(search));
        break;
    case "Field2":
        orderFunc = u => u.Field2;
        users = users.Where(u => u.Field2.Contains(search));
        break;
}

// If you need to get the total count, do it here:
var totalUserCount = users.Count();

// Apply sorting:
if (order_sort == "ASC")
{
    users = users.OrderBy(orderFunc);
}
else
{
    users = users.OrderByDescending(orderFunc);
}

// Apply paging:
users = users.Skip(Convert.ToInt32(limit_begin)).Take(Convert.ToInt32(limit_end));

除了 Convert.ToInt32,我会做一些其他的事情,比如 int.TryParse,但对于这个例子我没有。

编辑1:

如果您最终想要更强大的搜索,请查看 LinqKit 中的 PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx)。

编辑2:

我的示例只是在过滤部分中包含 sting 。当然,您可以为用户请求的特定过滤器自定义所有逻辑。如果他们在一个 int 上进行过滤,您可以将过滤器字符串转换为一个 int,然后可以在 lambda 表达式中与 == 进行比较。就像是:

int myId;
if (int.TryParse(search, out myId))
{
    users = users.Where(u => u.SomeIntegerField == myId);
}
于 2012-08-16T18:08:20.077 回答
0

原始问题的主题可以通过表达式树和反射轻松实现。

您可以在我为我的一次演讲制作的 github 存储库中查看将强类型 Sort \ Filter 从仅字符串列名称和值添加到 EF6 的工作示例

这是链接中类的排序功能示例

 public class GridRequestSort
    {
        public string PropName { get; set; }
        public bool IsDescending { get; set; }
    }

        private static IQueryable<T> WrapSort<T>(
            IQueryable<T> query,
            GridRequestSort sort,
            bool isFirst = false)
        {
            var propAccessExpr = GetPropAccesssLambdaExpr(typeof(T), sort.PropName);
            var orderMethodName = "";
            if (isFirst)
            {
                orderMethodName = sort.IsDescending ? "OrderByDescending" : "OrderBy";
            } 
            else
            {
                orderMethodName = sort.IsDescending ? "ThenByDescending" : "ThenBy";
            }

            var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == orderMethodName && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propAccessExpr.ReturnType);
            var newQuery = (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, propAccessExpr });
            return newQuery;
        }

        private static LambdaExpression GetPropAccesssLambdaExpr(Type type, string name)
        {
            var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            var param = Expression.Parameter(type);
            var propAccess = Expression.Property(param, prop.Name);
            var expr = Expression.Lambda(propAccess, param);
            return expr;
        }
于 2016-12-30T13:56:18.950 回答