我的項目中有一個擴展,讓我們用字符串對IEnumerable
進行排序,以便可以更動態地進行排序。將此LINQ轉換爲動態表達式樹
所以,如果我有這些模型:
public MyModel
{
public int Id {get; set;}
public string RecordName {get; set;}
public ChildModel MyChildren {get; set;}
}
public ChildModel
{
public int ChildModelId {get; set;}
public string ChildName {get; set;}
public DateTime SavedDate {get; set;}
}
我可以整理我的名單如下:
var myList = db.MyModel.Where(m => m.IsActive);
myList
.OrderBy(m => m.MyChildren
.OrderByDescending(c => c.SavedDate).FirstOrDefault().SavedDate);
或:
var myList = db.MyModel.Where(m => m.IsActive);
myList.OrderBy(m => m.MyChildren.Max(c => c.SavedDate);
但我想能根據用戶選項動態分類。所以,我想這樣的:
var myList = db.MyModel.Where(m => m.IsActive);
myList.OrderByField("MyChildren.SavedDate");
擴展方法我到目前爲止是這樣的:
public static class MkpExtensions
{
public static IEnumerable<T> OrderByField<T>(this IEnumerable<T> list, string sortExpression)
{
sortExpression += "";
string[] parts = sortExpression.Split(' ');
bool descending = false;
string fullProperty = "";
if (parts.Length > 0 && parts[0] != "")
{
fullProperty = parts[0];
if (parts.Length > 1)
{
descending = parts[1].ToLower().Contains("esc");
}
ParameterExpression inputParameter = Expression.Parameter(typeof(T), "p");
Expression propertyGetter = inputParameter;
foreach (string propertyPart in fullProperty.Split('.'))
{
var checkIfCollection = propertyGetter.Type.GetInterfaces()//(typeof (ICollection<>).FullName);
.Any(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(ICollection<>) || x.GetGenericTypeDefinition() == typeof(IEnumerable<>)));
if (checkIfCollection)
{
var pgType = propertyGetter.Type;
var childType = pgType.GetGenericArguments().Single();
var childProp = childType.GetProperty(propertyPart);
ParameterExpression childInParam = Expression.Parameter(childType, "c");
var propertyAccess = Expression.Property(childInParam, childProp);
var orderByExp = Expression.Lambda(propertyAccess, childInParam);
// At this point, orderByExp is c => c.ActionDate
// Now I want to build the expression tree to handle the order by
XXXXX This is where I need help.
}
else
{
// This handles a singular property. Like "MyChildren.ChildName"
// and this part does work
PropertyInfo prop = propertyGetter.Type.GetProperty(propertyPart);
if (prop == null)
throw new Exception("No property '" + fullProperty + "' in + " + propertyGetter.Type.Name + "'");
propertyGetter = Expression.Property(propertyGetter, prop);
}
}
Expression conversion = Expression.Convert(propertyGetter, typeof(object));
var getter = Expression.Lambda<Func<T, object>>(conversion, inputParameter).Compile();
if (descending)
{
// This would be like
// list.OrderByDescending(m => m.MyChildren
// .OrderByDescending(c => c.SavedDate).FirstOrDefault().SavedDate);
return list.OrderByDescending(getter);
}
else
{
// This would be like
// list.OrderBy(m => m.MyChildren
// .OrderByDescending(c => c.SavedDate).FirstOrDefault().SavedDate);
return list.OrderBy(getter);
}
}
return list;
}
}
可能的複製http://stackoverflow.com/問題/ 41244/dynamic-linq-orderby-on-ienumerablet) – ASh
@Ash我看不到如何處理集合屬性的屬性的排序。 –