Note that there are some explanatory texts on larger screens.

plurals
  1. POComplex LINQ sorting using Lambda Expressions
    primarykey
    data
    text
    <p>Does anyone have/know of an IQueryable.OrderBy extension that takes an Expression (retrieved, for example, by Reflection)? I believe the function would look something like this:</p> <pre><code>public static IQueryable&lt;TEntity&gt; OrderBy&lt;TEntity&gt; (this IQueryable&lt;TEntity&gt; source, Expression sortExpression) </code></pre> <p>Expression would be assumed to be an <code>Expression&lt;Func&lt;TEntity, T&gt;&gt;</code> where TEntity is the same object being sorted on, and T is a type that needs to be determined in order to create the new IQueryable.</p> <p>I've found many examples of extensions that take a string, including Dynamic Linq, like this: </p> <pre><code>public static IQueryable&lt;TEntity&gt; OrderBy&lt;TEntity&gt;( this IQueryable&lt;TEntity&gt; source, string sortExpression) </code></pre> <p>If it's possible to take the string and use Reflection to look up the type from the object in question, it should also be possible to take the Expression, and get the value type which is right there IN the Expression.</p> <hr> <p>Following is a detailed explanation of why I'd like to have this, which you may or may not need.</p> <p>I have a rather large list of complex records to sort. Because the list is so long, I prefer to have the sorting done on the database side. To handle more complex properties, I've created Expressions that provide the sorting functionality, like so:</p> <pre><code>if (model.sortExpression == "PlannedValue") { Expression&lt;Func&lt;BDopp, decimal&gt;&gt; sorter = BDopp.PlannedValueSorter; if (model.sortDirection == "DESC") opps = opps.OrderByDescending(sorter).AsQueryable(); else opps = opps.OrderBy(sorter).AsQueryable(); } </code></pre> <p>BDOpp.PlannedValueSorter retrieves a static expression from the object which allows sorting to be done without opps are still of type IQueryable:</p> <pre><code>public static Expression&lt;Func&lt;BDopp, decimal&gt;&gt; PlannedValueSorter { get { return z =&gt; z.BudgetSchedules .Where(s =&gt; s.Type == 1) .Sum(s =&gt; s.Value * s.Workshare * z.valueFactor / 100 / 100); } } </code></pre> <p>Sorting for simple properties is done with Extension methods that use Reflection to build an expression based on the name of the property passed as a string.</p> <p>This works well, but for the complex types, I still need branching logic, and I'd rather not do that. What I'd rather do is check for a static property containing the expression, and then simply apply it. I can get the expression like this:</p> <pre><code>PropertyInfo info = typeof(BDopp).GetProperty(model.sortExpression + "Sorter", BindingFlags.Static | BindingFlags.Public); Expression expr = (Expression)info.GetValue(null, null); </code></pre> <p>For the PlannedValue property, this gets me the expression sorted in PlannedValueSorter, which I already know works.</p> <hr> <h2>Update:</h2> <p>Various digging around has gotten me what I think might be some progress:</p> <pre><code>public static IQueryable&lt;TEntity&gt; OrderBy&lt;TEntity&gt;(this IQueryable&lt;TEntity&gt; source, Expression&lt;Func&lt;TEntity, dynamic&gt;&gt; sortExpression) { var unary = sortExpression.Body as UnaryExpression; Type actualExpressionType = unary.Operand.Type; </code></pre> <p>actualExpressionType is in fact the return type of the Expression (for this particular property, it's decimal).</p> <p>Unfortunately I'm mostly just working by trial and error, since I haven't yet wrapped my brain around how all this works, so my attempt to update the query like so is not working:</p> <pre><code> MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { typeof(TEntity), actualExpressionType }, source.Expression, sortExpression); return source.Provider.CreateQuery&lt;TEntity&gt;(resultExp); </code></pre> <p>It compiles okay, but the following error is thrown at runtime:</p> <blockquote> <p>No generic method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.</p> </blockquote>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload