Last active
June 28, 2022 07:25
-
-
Save RickyLin/903c27b040bf77d1febe8bd4a1f97590 to your computer and use it in GitHub Desktop.
Extension methods on Queryable/IQueryable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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