Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

Dynamic LINQ Methods

Continuing the Dynamic LINQ series, here are some hopefuly useful methods for performing LINQ queries in IQueryable or IQueryable<T> object, with String parameters. The available methods, so far, are:

  • GroupBy
  • OrderBy
  • Skip
  • Take
  • WhereEquals
  • WhereNotEquals

	public static class QueryableExtensions
	{
		public static IQueryable<T&> WhereNotEquals<T&>(this IQueryable<T&> query, String propertyName, Object value)
		{
			return (WhereNotEquals(query as IQueryable, propertyName, value) as IQueryable<T&>);
		}

		public static IQueryable WhereNotEquals(this IQueryable query, String propertyName, Object value)
		{
			Type propertyType = query.GetType().GetGenericArguments() [ 0 ];
			MethodInfo whereMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "Where").ToArray() [ 0 ].MakeGenericMethod(propertyType);

			ParameterExpression parameter = Expression.Parameter
			(
				propertyType,
				"m"
			);

			MemberExpression member = Expression.MakeMemberAccess
			(
				parameter,
				propertyType.GetProperty(propertyName)
			);

			BinaryExpression equal = ParameterExpression.NotEqual
			(
				member,
				(value != null) ? Expression.Constant(value, value.GetType()) : null
			);

			LambdaExpression lambda = Expression.Lambda
			(
				typeof(Func<,>).MakeGenericType(propertyType, typeof(Boolean)),
				equal,
				member.Expression as ParameterExpression
			);

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

			return (query);
		}

		public static IQueryable<T&> WhereEquals<T&>(this IQueryable<T&> query, String propertyName, Object value)
		{
			return (WhereEquals(query as IQueryable, propertyName, value) as IQueryable<T&>);
		}

		public static IQueryable WhereEquals(this IQueryable query, String propertyName, Object value)
		{
			Type propertyType = query.GetType().GetGenericArguments() [ 0 ];
			MethodInfo whereMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "Where").ToArray() [ 0 ].MakeGenericMethod(propertyType);

			ParameterExpression parameter = Expression.Parameter
			(
				propertyType,
				"m"
			);

			MemberExpression member = Expression.MakeMemberAccess
			(
				parameter,
				propertyType.GetProperty(propertyName)
			);

			BinaryExpression equal = ParameterExpression.Equal
			(
				member,
				(value != null) ? Expression.Constant(value, value.GetType()) : null
			);

			LambdaExpression lambda = Expression.Lambda(typeof(Func<,>).MakeGenericType(propertyType, typeof(Boolean)), equal, member.Expression as ParameterExpression);

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

			return(query);
		}

		public static IQueryable<T&> GroupBy<T&>(this IQueryable<T&> query, String propertyName)
		{
			return (GroupBy(query as IQueryable, propertyName) as IQueryable<T&>);
		}

		public static IQueryable GroupBy(this IQueryable query, String propertyName)
		{
			Type propertyType = query.GetType().GetGenericArguments() [ 0 ];
			PropertyInfo property = propertyType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
			MethodInfo groupByMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "GroupBy" && m.GetParameters().Length == 2).ToArray() [ 0 ].MakeGenericMethod(propertyType, property.PropertyType);

			ParameterExpression parameter = Expression.Parameter
			(
				propertyType,
				"m"
			);

			MemberExpression member = Expression.MakeMemberAccess
			(
				parameter,
				propertyType.GetProperty(propertyName)
			);
	
			LambdaExpression lambda = Expression.Lambda
			(
				typeof(Func<,>).MakeGenericType(propertyType, property.PropertyType),
				member,
				member.Expression as ParameterExpression
			);

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

			return (query);
		}

		public static IQueryable<T&> OrderBy<T&>(this IQueryable<T&> query, params String [] properties)
		{
			return (OrderBy(query as IQueryable, properties) as IQueryable<T&>);
		}

		public static IQueryable OrderBy(this IQueryable query, params String [] properties)
		{
			properties = (properties == null) ? new String [ 0 ] : properties.Distinct().ToArray();

			Type propertyType = query.GetType().GetGenericArguments()[ 0 ];
			MethodInfo orderByMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "OrderBy").ToArray() [ 0 ];
			MethodInfo orderByDescMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "OrderByDescending").ToArray() [ 0 ];
			MethodInfo orderThenByMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "ThenBy").ToArray() [ 0 ];
			MethodInfo orderThenByDescMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "ThenByDescending").ToArray() [ 0 ];
			String [] parts = null;
			MethodInfo method = null;
			PropertyInfo property = null;
			MemberExpression member = null;
			LambdaExpression orderBy = null;

			for (Int32 i = 0; i < properties.Length; ++i)
			{
				parts = properties[ i ].Split(' ');

				property = propertyType.GetProperty(parts[ 0 ], BindingFlags.Instance | BindingFlags.Public);

				if ((parts.Length == 1) || (parts [ 1 ].Equals("asc", StringComparison.OrdinalIgnoreCase) == true))
				{
					if (i == 0)
					{
						method = orderByMethod.MakeGenericMethod(propertyType, property.PropertyType);
					}
					else
					{
						method = orderThenByMethod.MakeGenericMethod(propertyType, property.PropertyType);
					}
				}
				else if (parts[ 1 ].Equals("desc", StringComparison.OrdinalIgnoreCase) == true)
				{
					if (i == 0)
					{
						method = orderByDescMethod.MakeGenericMethod(propertyType, property.PropertyType);
					}
					else
					{
						method = orderThenByDescMethod.MakeGenericMethod(propertyType, property.PropertyType);
					}
				}

				member = Expression.MakeMemberAccess
				(
					Expression.Parameter(propertyType, "n"),
					property
				);

				orderBy = Expression.Lambda
				(
					member,
					member.Expression as ParameterExpression
				);

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

			return (query);
		}

		public static IQueryable Take(this IQueryable query, Int32 pageSize)
		{
			Type propertyType = query.GetType().GetGenericArguments() [ 0 ];
			MethodInfo takeMethod = typeof(Queryable).GetMethod("Take", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(propertyType);

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

			return (query);
		}

		public static IQueryable Skip(this IQueryable query, Int32 pageIndex)
		{
			Type propertyType = query.GetType().GetGenericArguments() [ 0 ];
			MethodInfo skipMethod = typeof(Queryable).GetMethod("Skip", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(propertyType);

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

			return (query);
		}
	}

Here are some examples:


IQueryable q = ...;

q = q.OrderBy("NAME asc", "BIRTHDAY desc");

q = q.WhereEquals("NAME", "bla");

q = q.GroupBy("PROFILE");

q = q.Take(10);

Bookmark and Share

Comments

Raghuraman said:

Cool.. Another Nice Chapter.

Thanks a Lot !!!

BTW Any updates about Results to MS Beta Exams ?

# June 29, 2010 4:59 PM

Twitter Trackbacks for Dynamic LINQ Methods - Development With A Dot [asp.net] on Topsy.com said:

Pingback from  Twitter Trackbacks for                 Dynamic LINQ Methods - Development With A Dot         [asp.net]        on Topsy.com

# June 29, 2010 9:23 PM

Ricardo Peres said:

Francis:

Yes, I know... I did mention it on my first post on Dynamic LINQ, you just have to remove somethings from the project and recompile it, in order to have a reusable assembly (I added one on the post).

Raghuraman:

Nothing, yet! :-)

# June 30, 2010 4:08 AM

Specific First Record via LinQ « Joe Mele’s Weblog said:

Pingback from  Specific First Record via  LinQ &laquo;  Joe Mele&#8217;s Weblog

# September 9, 2010 7:37 AM