Updated .OrderBy implementation to support OrderBy,OrderByDescending,ThenBy,ThenByDescending properly on DynamicNodeList

Usage is: @foreach(var item in home.ChildItems.OrderBy("catCount, colour desc"))
If you use the simple form of home.ChildItems.OrderBy("catCount") it will use a simpler/faster implementation
This commit is contained in:
agrath@gmail.com
2011-02-17 19:07:22 -13:00
parent d9f420d45a
commit 3a30c285fe
3 changed files with 110 additions and 26 deletions

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace umbraco.MacroEngines
{
public static class DynamicNodeListOrdering
{
private static object Reduce(Func<DynamicNode, object> func, DynamicNode node)
{
var value = func(node);
while (value is Func<DynamicNode, object>)
{
value = (value as Func<DynamicNode, object>)(node);
}
return value;
}
public static IOrderedQueryable<DynamicNode> OrderBy(object source, object key)
{
IEnumerable<DynamicNode> typedSource = source as IEnumerable<DynamicNode>;
LambdaExpression lambda = key as LambdaExpression;
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.OrderBy(x => Reduce(func, x)).AsQueryable();
return result;
}
public static IOrderedQueryable<DynamicNode> ThenBy(object source, object key)
{
IOrderedQueryable<DynamicNode> typedSource = source as IOrderedQueryable<DynamicNode>;
LambdaExpression lambda = key as LambdaExpression;
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.ThenBy(x => Reduce(func, x)).AsQueryable();
return result;
}
public static IOrderedQueryable<DynamicNode> OrderByDescending(object source, object key)
{
IEnumerable<DynamicNode> typedSource = source as IEnumerable<DynamicNode>;
LambdaExpression lambda = key as LambdaExpression;
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.OrderByDescending(x => Reduce(func, x)).AsQueryable();
return result;
}
public static IOrderedQueryable<DynamicNode> ThenByDescending(object source, object key)
{
IOrderedQueryable<DynamicNode> typedSource = source as IOrderedQueryable<DynamicNode>;
LambdaExpression lambda = key as LambdaExpression;
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
IOrderedQueryable<DynamicNode> result = (IOrderedQueryable<DynamicNode>)typedSource.ThenByDescending(x => Reduce(func, x)).AsQueryable();
return result;
}
}
}

View File

@@ -84,45 +84,73 @@ namespace System.Linq.Dynamic
public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
{
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), ordering, values);
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
if (!ordering.Contains(","))
{
//source list is DynamicNode and the lambda returns a Func<object>
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
return typedSource.OrderBy(delegate(DynamicNode node)
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), ordering, values);
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
{
object value = -1;
var firstFuncResult = func(node);
if (firstFuncResult is Func<DynamicNode, object>)
//source list is DynamicNode and the lambda returns a Func<object>
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
return typedSource.OrderBy(delegate(DynamicNode node)
{
value = (firstFuncResult as Func<DynamicNode, object>)(node);
}
return value;
}).AsQueryable();
object value = -1;
var firstFuncResult = func(node);
if (firstFuncResult is Func<DynamicNode, object>)
{
value = (firstFuncResult as Func<DynamicNode, object>)(node);
}
return value;
}).AsQueryable();
}
}
else
bool isDynamicNodeList = false;
if (typedSource != null)
{
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression[] parameters = new ParameterExpression[] {
isDynamicNodeList = true;
}
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings)
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings)
{
if (!isDynamicNodeList)
{
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type[] { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery(queryExpr);
else
{
//reroute each stacked Expression.Call into our own methods that know how to deal
//with DynamicNode
queryExpr = Expression.Call(
typeof(DynamicNodeListOrdering),
o.Ascending ? methodAsc : methodDesc,
null,
queryExpr,
Expression.Quote(Expression.Lambda(o.Selector, parameters))
);
}
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
if (isDynamicNodeList)
{
return typedSource.Provider.CreateQuery(queryExpr);
}
return source.Provider.CreateQuery(queryExpr);
}
public static IQueryable Take(this IQueryable source, int count)

View File

@@ -63,6 +63,7 @@
<ItemGroup>
<Compile Include="DLRScriptingEngine.cs" />
<Compile Include="DynamicDictionary.cs" />
<Compile Include="DynamicNodeListOrdering.cs" />
<Compile Include="DynamicQueryableBinders.cs" />
<Compile Include="DynamicMedia.cs" />
<Compile Include="DynamicNode.cs" />