Last active
October 25, 2018 15:56
-
-
Save sgissinger/ed2669f9418747895a9e5d164059cc76 to your computer and use it in GitHub Desktop.
Dynamic Linq
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
public interface IFilterable | |
{ | |
string ColumnName { get; } | |
string Operator { get; } | |
string Value { get; } | |
} |
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
public interface ISortable | |
{ | |
string ColumnName { get; } | |
string Direction { get; } | |
bool IsDescending { get; } | |
} |
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
public static class LinqExtensions | |
{ | |
public static IQueryable<T> OrderBy<T>(this IEnumerable<T> source, IEnumerable<ISortable> sortables) | |
{ | |
return source.AsQueryable().OrderBy(sortables); | |
} | |
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, IEnumerable<ISortable> sortables) | |
{ | |
if (source == null) | |
throw new ArgumentNullException("source"); | |
if (sortables == null) | |
throw new ArgumentNullException("orders"); | |
var type = typeof(T); | |
var first = true; | |
foreach (var sortable in sortables) | |
{ | |
var command = first ? "OrderBy" : "ThenBy"; | |
if (sortable.IsDescending) | |
command = string.Format("{0}Descending", command); | |
var property = type.GetProperty(sortable.ColumnName); | |
var parameter = Expression.Parameter(type, "p"); | |
var propertyAccess = Expression.MakeMemberAccess(parameter, property); | |
var lambdaExpression = Expression.Lambda(propertyAccess, parameter); | |
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType }, | |
source.Expression, Expression.Quote(lambdaExpression)); | |
source = source.Provider.CreateQuery<T>(resultExpression); | |
first = false; | |
} | |
return source; | |
} | |
public static IQueryable<T> Where<T>(this IEnumerable<T> source, IEnumerable<IFilterable> filterables) | |
{ | |
return source.AsQueryable().Where(filterables); | |
} | |
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<IFilterable> filterables) | |
{ | |
if (source == null) | |
throw new ArgumentNullException("source"); | |
if (filterables == null) | |
throw new ArgumentNullException("filters"); | |
var type = typeof(T); | |
foreach (var filterable in filterables) | |
{ | |
var property = type.GetProperty(filterable.ColumnName); | |
// TODO: Extend in order to manage other cases, this one only take care of string equalities | |
if (property.PropertyType == typeof(string)) | |
{ | |
var parameter = Expression.Parameter(type, "p"); | |
var propertyAccess = Expression.MakeMemberAccess(parameter, property); | |
var value = Expression.Constant(filterable.Value); | |
var expression = Expression.Equal(value, value); | |
if (filterable.Operator == "eq") | |
expression = Expression.Equal(propertyAccess, value); | |
else if (filterable.Operator == "like") | |
expression = LikeOrNotLike(propertyAccess, value, true); | |
else if (filterable.Operator == "notLike") | |
expression = LikeOrNotLike(propertyAccess, value, false); | |
var lambdaExpression = Expression.Lambda(expression, parameter); | |
var resultExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { type }, | |
source.Expression, lambdaExpression); | |
source = source.Provider.CreateQuery<T>(resultExpression); | |
} | |
} | |
return source; | |
} | |
private static BinaryExpression LikeOrNotLike(MemberExpression propertyAccess, ConstantExpression value, bool like) | |
{ | |
var cmp = Expression.Constant(StringComparison.InvariantCulture); | |
var indexOf = typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) }); | |
var toLower = typeof(string).GetMethod("ToLower", Type.EmptyTypes); | |
var valueToLower = Expression.Call(value, toLower); | |
var propertyToLower = Expression.Call(propertyAccess, toLower); | |
var left = Expression.Call(propertyToLower, indexOf, valueToLower, cmp); | |
BinaryExpression expression; | |
if (like) | |
{ | |
var right = Expression.Constant(0, typeof(int)); | |
expression = Expression.GreaterThanOrEqual(left, right); | |
} | |
else | |
{ | |
var right = Expression.Constant(-1, typeof(int)); | |
expression = Expression.Equal(left, right); | |
} | |
return expression; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment