我已经为我的EF通用存储库创建了一个orderby表达式,如下所示 string command = orderByDesc? “OrderByDescending”:“OrderBy”;
var type = typeof(T);
var property = type.GetProperty(orderby);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
items.Expression, Expression.Quote(orderByExpression));
items = items.Provider.CreateQuery<T>(resultExpression);
现在我想创建带有2列的Expression进行排序,但却找不到有用的东西。
请帮我创建一个包含2列的orderby表达式。
答案 0 :(得分:1)
在LINQ中按多列排序可以通过调用OrderBy()
,然后调用ThenBy()
进行零次或多次调用来实现。您只需拨打一次OrderBy()
即可完成此操作。
例如,如果您希望按列a
和b
进行排序,则必须生成类似于以下内容的表达式:
items.OrderBy(p => p.a).ThenBy(p => p.b)
答案 1 :(得分:0)
我不知道接受的答案是如何被接受的,因为OP询问如何为多列排序方案创建表达树。
有时您必须使用表达式树手动构建 OrderBy 语句,因为您不知道用户要对哪些列进行排序。例如,当您有一个使用Datatables构建的网格并且某些列是可排序的时,用户可以SHIFT单击列标题以按多个列进行排序:
此屏幕快照显示用户希望按Cassette(string
)和Slot Number(double
)对网格进行排序。
在构建 Expression Tree 进行排序时,这里最棘手的部分是,第一次您需要使用OrderBy*
,而第二次及以后,您需要切换为使用ThenBy*
。
我将演示如何使用IQueryable
上的扩展方法做到这一点:
namespace DataTables.AspNet.Core
{
public interface ISort
{
int Order { get; }
SortDirection Direction { get; }
}
public enum SortDirection
{
Ascending = 0,
Descending = 1
}
}
namespace DL.SO.Framework.Mvc.DataTables.Extensions
{
public static class QueryableExtensions
{
public static IQueryable<TModel> OrderByColumns<TModel>(
this IQueryable<TModel> collection,
IDictionary<string, ISort> sortedColumns)
{
// Basically sortedColumns contains the columns user wants to sort by, and
// the sorting direction.
// For my screenshot, the sortedColumns looks like
// [
// { "cassette", { Order = 1, Direction = SortDirection.Ascending } },
// { "slotNumber", { Order = 2, Direction = SortDirection.Ascending } }
// ]
bool firstTime = true;
// The type that represents each row in the table
var itemType = typeof(TModel);
// Name the parameter passed into the lamda "x", of the type TModel
var parameter = Expression.Parameter(itemType, "x");
// Loop through the sorted columns to build the expression tree
foreach (var sortedColumn in sortedColumns.OrderBy(sc => sc.Value.Order))
{
// Get the property from the TModel, based on the key
var prop = Expression.Property(parameter, sortedColumn.Key);
// Build something like x => x.Cassette or x => x.SlotNumber
var exp = Expression.Lamda(prop, parameter);
// Based on the sorting direction, get the right method
string method = String.Empty;
if (firstTime)
{
method = sortedColumn.Value.Direction == SortDirection.Ascending
? "OrderBy"
: "OrderByDescending";
firstTime = false;
}
else
{
method = sortedColumn.Value.Direction == SortDirection.Ascending
? "ThenBy"
: "ThenByDescending";
}
// itemType is the type of the TModel
// exp.Body.Type is the type of the property. Again, for Cassette, it's
// a String. For SlotNumber, it's a Double.
Type[] types = new Type[] { itemType, exp.Body.Type };
// Build the call expression
// It will look something like:
// OrderBy*(x => x.Cassette) or Order*(x => x.SlotNumber)
// ThenBy*(x => x.Cassette) or ThenBy*(x => x.SlotNumber)
var mce = Expression.Call(typeof(Queryable), method, types,
collection.Expression, exp);
// Now you can run the expression against the collection
collection = collection.Provider.CreateQuery<TModel>(mce);
}
return collection;
}
}
}
注意:OrderBy *表示OrderBy或OrderByDescending。对于ThenBy *也是如此。