Dynamic Paging and Sorting

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<T> ApplyPagingAndSorting<T>(IEnumerable<T> enumerable, Int32 pageSize, Int32 pageIndex, params String [] orderByColumns)
{
	return (ApplyPagingAndSorting(enumerable, typeof(T), pageSize, pageIndex, orderByColumns) as List<T>);
}

List<DateTime> list = new List<DateTime> { 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<DateTime> sortedList = ApplyPagingAndSorting(list, 3, 0, "Year", "Month", "Day");

Bookmark and Share

                             

No Comments