Skip to content

Instantly share code, notes, and snippets.

@ismaelgasparin
Last active November 5, 2022 23:07
Show Gist options
  • Save ismaelgasparin/30f2a6f144b0a693ab918c6b4cb83d58 to your computer and use it in GitHub Desktop.
Save ismaelgasparin/30f2a6f144b0a693ab918c6b4cb83d58 to your computer and use it in GitHub Desktop.
Queryable helper
using System.Collections.Generic;
using System.Linq.Expressions;
namespace System.Linq
{
public static class QueryableHelper
{
public static IQueryable<TEntity> Search<TEntity>(this IQueryable<TEntity> query, string searchValue, params Expression<Func<TEntity, string>>[] propertiesToSearch)
{
if (string.IsNullOrEmpty(searchValue)) return query;
var expressions = new List<Expression>();
var parameterExpression = Expression.Parameter(typeof(TEntity), "i");
var searchExpression = Expression.Constant(searchValue);
foreach (var expression in propertiesToSearch)
{
var containsExpression =
Expression.Call(
expression.Body,
typeof(string).GetMethod("Contains", new[] { typeof(string) }),
searchExpression);
expressions.Add(containsExpression);
}
var predicateBody = new ParameterReplacer(parameterExpression)
.Visit(expressions[0]);
for (var i = 1; i < expressions.Count; i++)
{
predicateBody = new ParameterReplacer(parameterExpression)
.Visit(Expression.OrElse(predicateBody, expressions[i]));
}
var whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new[] { query.ElementType },
query.Expression,
Expression.Lambda<Func<TEntity, bool>>(predicateBody, parameterExpression));
return query.Provider.CreateQuery<TEntity>(whereCallExpression);
}
private static MemberExpression CreateExpression(ParameterExpression param, string propertyName)
{
Expression body = param;
foreach (var member in propertyName.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries))
{
body = Expression.PropertyOrField(body, member.ToCapitalize());
}
return (MemberExpression)body;
}
public static IQueryable<TEntity> Order<TEntity>(this IQueryable<TEntity> query, string propertyName, string direction)
{
var type = typeof(TEntity);
if (string.IsNullOrWhiteSpace(propertyName)) return query;
var parameter = Expression.Parameter(type, "p");
var propertyAccess = CreateExpression(parameter, propertyName);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(
typeof(Queryable),
direction.Equals("desc", StringComparison.OrdinalIgnoreCase) ? "OrderByDescending" : "OrderBy",
new[] { type, propertyAccess.Type },
query.Expression,
Expression.Quote(orderByExpression));
return query.Provider.CreateQuery<TEntity>(resultExpression);
}
internal class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(_parameter);
}
internal ParameterReplacer(ParameterExpression parameter)
{
_parameter = parameter;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment