This should help. However, for this you will need a specific type of anonymous type. My LinqPropertyChain will not work with it, since it will be difficult to create Expression<Func<Anonymous, Person>> , while its anonymous.
Expression<Func<Person, object>> orderBy = x => x.Name; using(var dbContext = new MyDbContext()) { var keyword = "term"; var startsWithResults = dbContext.People .Where(x => x.Name.StartsWith(keyword)) .Select(x => new { Rank = 1, Entity = x, }); var containsResults = dbContext.People .Where(x => !startsWithResults.Select(y => y.Entity.Id).Contains(x.Id)) .Where(x => x.Name.Contains(keyword)) .Select(x => new { Rank = 2, Entity = x, }); var rankedResults = startsWithResults.Concat(containsResults) .OrderBy(x => x.Rank) .ThenBy(LinqPropertyChain.Chain(x => x.Entity, orderBy));
Figured out a way to do this with less Explicite Generics.
Expression<Func<Person, object>> orderBy = x => x.Name; Expression<Func<Foo, Person>> personExpression = x => x.Person; var helper = new ExpressionChain(personExpression); var chained = helper.Chain(orderBy).Expression; // Define other methods and classes here public class ExpressionChain<TInput, TOutput> { private readonly Expression<Func<TInput, TOutput>> _expression; public ExpressionChain(Expression<Func<TInput, TOutput>> expression) { _expression = expression; } public Expression<Func<TInput, TOutput>> Expression { get { return _expression; } } public ExpressionChain<TInput, TChained> Chain<TChained> (Expression<Func<TOutput, TChained>> chainedExpression) { var visitor = new Visitor(new Dictionary<ParameterExpression, Expression> { {_expression.Parameters[0], chainedExpression.Body} }); var lambda = Expression.Lambda<Func<TInput, TOutput>>(newBody, outter.Parameters); return new ExpressionChain(lambda); } private class Visitor : ExpressionVisitor { private readonly Dictionary<ParameterExpression, Expression> _replacement; public Visitor(Dictionary<ParameterExpression, Expression> replacement) { _replacement = replacement; } protected override Expression VisitParameter(ParameterExpression node) { if (_replacement.ContainsKey(node)) return _replacement[node]; else { return node; } } } }
source share