基于子实体的属性构建OrderBy Lambda表达式

我正在尝试使用lambda表达式生成LINQ OrderBy子句,其中实体的列名称作为字符串的输入(在下面的“sortOn”变量中)。

下面的代码适用于sortOn值,如生成lambda的“Code”

 p => p.Code 

但我还想对lambda可能存在的子实体进行排序

 p => p.Category.Description 

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

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

此代码适用于简单的情况:

 var param = Expression.Parameter(typeof (Product), "p"); var sortExpression = Expression.Lambda<Func>( Expression.Property(param, sortOn), param); if (sortAscending ?? true) { products = products.OrderBy(sortExpression); } else { products = products.OrderByDescending(sortExpression); } 

此问题的用例是显示数据网格并能够对数据进行排序,只需将要排序的列名称传递回服务器即可。 我想使解决方案通用,但现在已开始使用特定类型(示例中的产品)。

这将生成正确的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>(parent, param); 

您可以使用动态LINQ查询库轻松完成此操作。 假设您具有ProductIQueryable实现 ,您可以轻松地执行以下操作:

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

博客文章有一个指向库的链接 ,你必须自己在你的解决方案中构建/包含项目,但它运行得很好,并且解析非常强大。 它可以防止您自己编写解析代码; 即使对于这么简单的事情,如果要求扩展,图书馆也会覆盖你,而本土解决方案却没有。

它还有许多其他动态运算符( SelectWhere等),因此您可以执行其他动态操作。

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

如果你不需要表达式,怎么样:

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

嗨,你也可以创建一个扩展方法,可以排序到任何深度,而不仅仅是孩子

  public static IEnumerable CustomOrderBy(this IEnumerable source, Func keySelector) { List list=new List(); List returnList=new List(); List indexList = new List(); 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 = new List{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); } } 

它的自定义方法现在它只适用于字符串属性,但是可以使用generics来重新设置它以适用于任何基本类型。 我希望这将有所帮助。

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

 public static IQueryable OrderBy(this IQueryable 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(orderByExpression); } catch (Exception e) { return query; } } 

我的解决方案中使用的CreateExpression方法在本文中定义。

OrderBy扩展方法的用法如下。

 IQueryable q = [Your database context].Foos.AsQueryable(); IQueryable 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方法相同的post。

希望您觉得这篇文章很有帮助。