12 April, 2010

Dynamic Paging and Sorting

Dynamic Paging and Sorting: By Ricardo Peres Asp.net WebLogs
Since .NET 3.5 brought us LINQ and expressions, I became a great fan of these technologies. There are times, however, when strong typing cannot be used - for example, when you are developing an ObjectDataSource and you need to do paging having just a column name, a page index and a page size, so I set out to fix this. Yes, I know about Dynamic LINQ, and even talked on it previously, but there's no need to add this extra assembly.
So, without further delay, here's the code, in both generic and non-generic versions:
public static IList ApplyPagingAndSorting(IEnumerable enumerable, Type elementType, Int32 pageSize, Int32 pageIndex, params String [] orderByColumns)
{
MethodInfo asQueryableMethod = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => (m.Name == "AsQueryable") && (m.ContainsGenericParameters == false)).Single();
IQueryable query = (enumerable is IQueryable) ? (enumerable as IQueryable) : asQueryableMethod.Invoke(null, new Object [] { enumerable }) as IQueryable;

if ((orderByColumns != null) && (orderByColumns.Length > 0))
{
PropertyInfo orderByProperty = elementType.GetProperty(orderByColumns [ 0 ]);
MemberExpression member = Expression.MakeMemberAccess(Expression.Parameter(elementType, "n"), orderByProperty);
LambdaExpression orderBy = Expression.Lambda(member, member.Expression as ParameterExpression);
MethodInfo orderByMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "OrderBy").ToArray() [ 0 ].MakeGenericMethod(elementType, orderByProperty.PropertyType);

query = orderByMethod.Invoke(null, new Object [] { query, orderBy }) as IQueryable;

if (orderByColumns.Length > 1)
{
MethodInfo thenByMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "ThenBy").ToArray() [ 0 ].MakeGenericMethod(elementType, orderByProperty.PropertyType);
PropertyInfo thenByProperty = null;
MemberExpression thenByMember = null;
LambdaExpression thenBy = null;

for (Int32 i = 1; i < orderByColumns.Length; ++i)
{
thenByProperty = elementType.GetProperty(orderByColumns [ i ]);
thenByMember = Expression.MakeMemberAccess(Expression.Parameter(elementType, "n"), thenByProperty);
thenBy = Expression.Lambda(member, member.Expression as ParameterExpression);
query = thenByMethod.Invoke(null, new Object [] { query, thenBy }) as IQueryable;
}
}
}

if (pageSize > 0)
{
MethodInfo takeMethod = typeof(Queryable).GetMethod("Take", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elementType);
MethodInfo skipMethod = typeof(Queryable).GetMethod("Skip", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elementType);

query = skipMethod.Invoke(null, new Object [] { query, pageSize * pageIndex }) as IQueryable;
query = takeMethod.Invoke(null, new Object [] { query, pageSize }) as IQueryable;
}

MethodInfo toListMethod = typeof(Enumerable).GetMethod("ToList", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(elementType);
IList list = toListMethod.Invoke(null, new Object [] { query }) as IList;

return (list);
}

public static List ApplyPagingAndSorting(IEnumerable enumerable, Int32 pageSize, Int32 pageIndex, params String [] orderByColumns)
{
return (ApplyPagingAndSorting(enumerable, typeof(T), pageSize, pageIndex, orderByColumns) as List);
}

List list = new List { new DateTime(2010, 1, 1), new DateTime(1999, 1, 12), new DateTime(1900, 10, 10), new DateTime(1900, 2, 20), new DateTime(2012, 5, 5), new DateTime(2012, 1, 20) };
List sortedList = ApplyPagingAndSorting(list, 3, 0, "Year", "Month", "Day");

    

No comments:

Post a Comment

Suggestions are invited from readers