Skip to content

Instantly share code, notes, and snippets.

@onionhammer
Last active October 25, 2019 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onionhammer/5137cefeface774af96af905a76593b6 to your computer and use it in GitHub Desktop.
Save onionhammer/5137cefeface774af96af905a76593b6 to your computer and use it in GitHub Desktop.
ObjectQueryExtensions
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