Skip to content

Instantly share code, notes, and snippets.

@RickyLin
Last active June 28, 2022 07:25
Show Gist options
  • Save RickyLin/903c27b040bf77d1febe8bd4a1f97590 to your computer and use it in GitHub Desktop.
Save RickyLin/903c27b040bf77d1febe8bd4a1f97590 to your computer and use it in GitHub Desktop.
Extension methods on Queryable/IQueryable
using System;
using System.Linq.Expressions;
using System.Linq;
using System.Collections.Generic;
namespace Rvc.Utilities
{
// refer to System.Web.Query.Dynamic namespace
public static class IQueryableExtensions
{
/// <summary>
/// Append Order By query according to the orderByExpression
/// </summary>
/// <typeparam name="T">the return type of query</typeparam>
/// <param name="query">the query</param>
/// <param name="orderByExpression">e.g. "ColumnName", "ColumnName ASC", "ColumnName DESC"</param>
/// <returns></returns>
public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string orderByExpression)
{
if (string.IsNullOrEmpty(orderByExpression))
return query;
string propertyName, orderByMethod, methodAsc = "OrderBy", methodDesc = "OrderByDescending";
string[] orderByTokens;
ParameterExpression pe;
MemberExpression me;
Expression queryExpression = query.Expression;
IEnumerable<string> orderByExpressions = orderByExpression.Split(',').Select(s => s.Trim());
foreach (string strOrderBy in orderByExpressions)
{
orderByTokens = strOrderBy.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
propertyName = orderByTokens[0];
if (orderByTokens.Length == 1)
orderByMethod = methodAsc;
else
orderByMethod = orderByTokens[1].Equals("DESC", StringComparison.OrdinalIgnoreCase) ? methodDesc : methodAsc;
pe = Expression.Parameter(query.ElementType);
me = Expression.Property(pe, propertyName);
queryExpression = Expression.Call(typeof(Queryable), orderByMethod, new Type[] { query.ElementType, me.Type }, queryExpression
, Expression.Quote(Expression.Lambda(me, pe)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return query.Provider.CreateQuery(queryExpression) as IQueryable<T>;
}
/// <summary>
/// Append a WHERE clause that combines all conditions with "OR" keyword like "condition1 OR condition2 OR condition 3"
/// </summary>
/// <typeparam name="T">the return type of query</typeparam>
/// <param name="query">the query</param>
/// <param name="conditions">condition expressions that will be combined with "OR" keyword</param>
/// <returns></returns>
public static IQueryable<T> WhereOr<T>(this IQueryable<T> query, IEnumerable<Expression<Func<T, bool>>> conditions)
{
if (conditions == null || conditions.Count() == 0)
return query;
Expression whereBody = null;
foreach (Expression<Func<T, bool>> condition in conditions)
{
if (whereBody == null)
whereBody = condition.Body;
else
whereBody = Expression.OrElse(whereBody, condition.Body);
}
ParameterExpression param = Expression.Parameter(typeof(T));
// Replace parameter expression of each "OR" sub expression with the given parameter expression
var paramReplacer = new ParameterExpressionReplaceVisitor(param);
whereBody = paramReplacer.Visit(whereBody);
Expression<Func<T, bool>> whereClause = Expression.Lambda<Func<T, bool>>(whereBody, param);
query = query.Where(whereClause);
return query;
}
private class ParameterExpressionReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
internal ParameterExpressionReplaceVisitor(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment