Last active
October 25, 2019 14:17
-
-
Save onionhammer/5137cefeface774af96af905a76593b6 to your computer and use it in GitHub Desktop.
ObjectQueryExtensions
This file contains hidden or 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; | |
using System.Linq.Expressions; | |
public static class ObjectQueryExtensions | |
{ | |
//FROM : http://vgermain.wordpress.com/2008/09/23/linq-to-sql-how-to-order-with-a-string-typed-expression/ (Modified algorithm - 3/15/2010) | |
public static IQueryable<TEntity> OrderByExpression<TEntity>( | |
this IQueryable<TEntity> source, string sortExpression) | |
{ | |
if (sortExpression == null) | |
return source; | |
// Remember that for ascending order GridView just returns the column name and | |
// for descending it returns column name followed by DESC keyword | |
// Therefore we need to examine the sortExpression and separate out Column Name and | |
// order (ASC/DESC) | |
var (propName, dir) = sortExpression.SplitTwo(' '); | |
// Order by method name | |
var orderByName = string.Equals(dir, "desc", StringComparison.OrdinalIgnoreCase) | |
// Order by DESC | |
? nameof(Queryable.OrderByDescending) | |
// Order by ASC | |
: nameof(Queryable.OrderBy); | |
var (orderByExp, typeArgs) = GetRootDeclaringType(typeof(TEntity), propName); | |
var resultExp = Expression.Call( | |
type: typeof(Queryable), | |
methodName: orderByName, | |
typeArguments: typeArgs, | |
arguments: new[] { | |
source.Expression, | |
Expression.Quote(orderByExp) | |
}); | |
return source.Provider.CreateQuery<TEntity>(resultExp); | |
} | |
/// <summary> | |
/// Split into two strings | |
/// </summary> | |
public static (string, string) SplitTwo(this string input, char id) | |
{ | |
var index = input.IndexOf(id, 1); | |
return index == -1 | |
? (input, null) | |
: (input[..index], input[(index + 1)..]); | |
} | |
/// <summary> | |
/// Generate property lambda | |
/// </summary> | |
static (LambdaExpression lambda, Type[] typeArgs) GetRootDeclaringType(Type root, string propertyPath) | |
{ | |
var (current, next) = propertyPath.SplitTwo('.'); | |
var declaringType = root.GetProperty(current).DeclaringType; | |
var child = declaringType.GetProperty(current); | |
var parameter = Expression.Parameter(root, "p"); | |
var (path, resultType) = next == null | |
? (Expression.MakeMemberAccess(parameter, child), child.PropertyType) | |
: GeneratePropertyExpression(Expression.MakeMemberAccess(parameter, child), next); | |
return (lambda: Expression.Lambda(path, parameter), | |
typeArgs: new[] { root, resultType }); | |
} | |
/// <summary> | |
/// Generate expression from path recursively | |
/// </summary> | |
static (Expression path, Type resultType) GeneratePropertyExpression(Expression parent, string path) | |
{ | |
var (current, next) = path.SplitTwo('.'); | |
var child = parent.Type.GetProperty(current); | |
return next == null | |
? (Expression.MakeMemberAccess(parent, child), child.PropertyType) | |
: GeneratePropertyExpression(Expression.Property(parent, child), next); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment