Skip to content

Instantly share code, notes, and snippets.

@khalidabuhakmeh
Created December 3, 2015 23:57
Show Gist options
  • Save khalidabuhakmeh/14f4f2e10e777bbb35d2 to your computer and use it in GitHub Desktop.
Save khalidabuhakmeh/14f4f2e10e777bbb35d2 to your computer and use it in GitHub Desktop.
public static class SearchExtensions
{
public static IQueryable<T> Search<T>(this IQueryable<T> value, object search)
{
if (search == null)
{
return value;
}
var filterProperties = search
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.CanRead)
.Where(x => x.PropertyType == typeof(string) || (typeof(IEnumerable).IsAssignableFrom(x.PropertyType) &&
x.PropertyType != typeof(string)));
var validValueProperties = typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.CanRead)
.ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);
var type = typeof(T);
var stringType = typeof(string);
var parameter = Expression.Parameter(type, "x");
var containsMethod = stringType.GetMethod("Contains", new[] { stringType });
Expression orExpressions = null;
foreach (var property in filterProperties)
{
PropertyInfo validValueProperty;
validValueProperties.TryGetValue(property.Name, out validValueProperty);
var filterPropertyValue = property.GetValue(search, null);
if (validValueProperty != null && filterPropertyValue != null)
{
if (typeof (IEnumerable).IsAssignableFrom(property.PropertyType) &&
property.PropertyType != typeof (string))
{
foreach (var arrayValue in (IEnumerable)filterPropertyValue)
{
if (arrayValue == null || arrayValue.GetType() != typeof (string))
continue;
orExpressions = OrExpressionBuilder<T>(arrayValue, parameter, validValueProperty, property, containsMethod, orExpressions);
}
}
else
{
orExpressions = OrExpressionBuilder<T>(property.GetValue(search, null), parameter, validValueProperty, property, containsMethod, orExpressions);
}
}
}
if (orExpressions != null)
{
var whereCallExpression = Expression.Call(
typeof (Queryable),
"Where",
new[] {value.ElementType},
value.Expression,
Expression.Lambda<Func<T, bool>>(orExpressions, new[] {parameter}));
return value.Provider.CreateQuery<T>(whereCallExpression);
}
else
{
return value;
}
}
private static Expression OrExpressionBuilder<T>(object value, ParameterExpression parameter,
PropertyInfo validValueProperty, PropertyInfo property, MethodInfo containsMethod, Expression orExpressions)
{
var searchExpression = Expression.Property(parameter, validValueProperty);
var searchTermExpression = Expression.Constant(value);
var callContainsMethod = Expression.Call(searchExpression, containsMethod, searchTermExpression);
orExpressions = orExpressions == null
? (Expression) callContainsMethod
: Expression.Or(orExpressions, callContainsMethod);
return orExpressions;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment