2012-07-13 25 views
10

我试图生成一个LINQ OrderBy子句使用lambda表达式,输入实体的列名称作为字符串(在下面的“sortOn”变量中)。建立一个OrderBy基于子实体的属性的Lambda表达式

下面的代码工作正常,像“代码” sortOn值产生的拉姆达

p => p.Code 

但我也想排序子实体,其中拉姆达可能是

p => p.Category.Description 

所以在这个例子中,我只想设置sortOn =“Category.Description”,并生成正确的lamdba表达式。

这可能吗?任何关于最佳方式的建议都会受到欢迎。

此代码工作正常进行的简单情况:

var param = Expression.Parameter(typeof (Product), "p"); 

var sortExpression = Expression.Lambda<Func<Product, object>>(
    Expression.Property(param, sortOn), param); 

if (sortAscending ?? true) 
{ 
    products = products.OrderBy(sortExpression); 
} 
else 
{ 
    products = products.OrderByDescending(sortExpression); 
} 

用例针对此问题正在显示的数据的网格,能够对数据进行排序,简单地通过将列名进行排序在回到服务器。我想使解决方案具有通用性,但现在已经开始使用特定类型(示例中的产品)。

+0

为什么你要手动创建表达式? – 2012-07-13 16:59:30

回答

18

这将产生正确的lambda表达式:

var sortOn = "Category.Description"; 
var param = Expression.Parameter(typeof(Product), "p"); 
var parts = sortOn.Split('.'); 

Expression parent = param; 

foreach (var part in parts) 
{ 
    parent = Expression.Property(parent, part); 
} 

var sortExpression = Expression.Lambda<Func<Product, object>>(parent, param); 
0

如果不需要表情,怎么样:

products = products.Orderby(p1 => p1.Code).ThenBy(p2 => p2.Category.Description) 
2

可以使用Dynamic LINQ Query Library轻松地做到这一点。假设你有一个ProductIQueryable<T> implementation,你可以很容易做到:

IQueryable<Product> products = ...; 

// Order by dynamically. 
products = products.OrderBy("Category.Description"); 

的博客帖子有一个link to the libary,你就必须建立/包含在解决方案中自己的项目,但它工作得非常好,解析非常健壮。它可以防止你自己写分析代码;即使对于如此简单的事情,如果需求扩大,图书馆也可以涵盖,而本土解决方案则不适用。

它还有一些其他动态操作符(SelectWhere等),因此您可以执行其他动态操作。

引擎盖下没有魔法,它只是解析你传递的字符串,然后根据解析结果创建lambda表达式。

+0

感谢您的建议。可能会标记为答案,但Tomek给了我想要的方法。肯定会考虑作为替代解决方案。 – Appetere 2012-07-14 19:54:17

0

嗨,你还可以创建一个扩展方法一样,可以进行排序,以任何深度的不只是孩子

 public static IEnumerable<TSource> CustomOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
    { 
     List<string> list=new List<string>(); 
     List<TSource> returnList=new List<TSource>(); 
     List<int> indexList = new List<int>(); 

     if (source == null) 
      return null; 
     if (source.Count() <= 0) 
      return source; 
     source.ToList().ForEach(sc=>list.Add(keySelector(sc).ToString())); //Extract the strings of property to be ordered 

     list.Sort(); //sort the list of strings 

     foreach (string l in list) // extract the list of indexes of source according to the order 
     { 
      int i=0; 
      //list.ForEach(l => 

       foreach (var s in source.ToList()) 
       { 
        if (keySelector(s).ToString() == l) 
         break; 
        i++; 
       } 
       indexList.Add(i); 
     } 
     indexList.ForEach(i=>returnList.Add(source.ElementAt(i))); //rearrange the source according to the above extracted indexes 
     return returnList; 
    } 
} 
public class Name 
{ 
    public string FName { get; set; } 
    public string LName { get; set; } 
} 
public class Category 
{ 
    public Name Name { get; set; } 
} 
public class SortChild 
{ 
    public void SortOn() 
    { 
     List<Category> category = new List<Category>{new Category(){Name=new Name(){FName="sahil",LName="chauhan"}}, 
      new Category(){Name=new Name(){FName="pankaj",LName="chauhan"}}, 
      new Category(){Name=new Name(){FName="harish",LName="thakur"}}, 
      new Category(){Name=new Name(){FName="deepak",LName="bakseth"}}, 
      new Category(){Name=new Name(){FName="manish",LName="dhamaka"}}, 
      new Category(){Name=new Name(){FName="arev",LName="raghaka"}} 
     }; 
     var a = category.CustomOrderBy(s => s.Name.FName); 

    } 

} 

其自定义的方法和现在它仅适用于字符串属性仅但它可以使用泛型来reactified为任何原始类型工作。我希望这将有所帮助。

0

这是一个扩展OrderBy方法适用于任何数量的嵌套参数。

public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string key, bool asc = true) 
{ 
    try 
    { 
    string orderMethodName = asc ? "OrderBy" : "OrderByDescending"; 
    Type type = typeof(T); 
    Type propertyType = type.GetProperty(key)?.PropertyType; ; 

    var param = Expression.Parameter(type, "x"); 
    Expression parent = param; 

    var keyParts = key.Split('.'); 
    for (int i = 0; i < keyParts.Length; i++) 
    { 
     var keyPart = keyParts[i]; 
     parent = Expression.Property(parent, keyPart); 

     if (keyParts.Length > 1) 
     { 
     if (i == 0) 
     { 
      propertyType = type.GetProperty(keyPart).PropertyType; 
     } 
     else 
     { 
      propertyType = propertyType.GetProperty(keyPart).PropertyType; 
     } 
     } 
    } 

    MethodCallExpression orderByExpression = Expression.Call(
     typeof(Queryable), 
     orderMethodName, 
     new Type[] { type, propertyType }, 
     query.Expression, 
     CreateExpression(type, key) 
    ); 

    return query.Provider.CreateQuery<T>(orderByExpression); 
    } 
    catch (Exception e) 
    { 
    return query; 
    } 
} 

CreateExpression方法这是在我的解决方案中使用的定义in this post

OrderBy扩展方法的用法如下。

IQueryable<Foo> q = [Your database context].Foos.AsQueryable(); 
IQueryable<Foo> p = null; 

p = q.OrderBy("myBar.name"); // Ascending sort 
// Or 
p = q.OrderBy("myBar.name", false); // Descending sort 
// Materialize 
var result = p.ToList(); 

类型Foo及其属性也从相同的柱作为方法CreateExpression

希望你觉得这个职位有帮助的。