Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to check if IQueryable<T> has OrderBy applied before before attempting Skip() and Take()
    primarykey
    data
    text
    <p>I am trying to build an extension method that will Paginated a query. But in order to avoid exception: System.NotSupportedException was unhandled by user code Message=The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.</p> <p>I'd like to check if OrderBy was applied and if not just return the query... Something like this:</p> <pre><code>public static IQueryable&lt;T&gt; Paginate&lt;T&gt;(this IQueryable&lt;T&gt; query, int page, int pageSize = 50, int total = -1) { // check if OrderBy was applied // THIS DOES NOT WORK!!! //try //{ // var orderedQueryable = query as IOrderedQueryable&lt;T&gt;; //} //catch (Exception) //{ // // if the cast throws OrderBy was not applied &lt;-- DOES NOT WORK!!! // return query; //} page = (page &lt; 1) ? 1 : page; var limit = (pageSize &lt;= 0 || (total &gt;= 0 &amp;&amp; pageSize &gt; total)) ? 50 : pageSize; var skip = (page - 1)*limit; return query.Skip(skip).Take(limit); } </code></pre> <p>To make things more <em>interesting</em>, I am using Mycrosoft's <a href="https://nuget.org/packages/System.Linq.Dynamic" rel="nofollow">Dynamic Expression API</a> (aka Dynamic LINQ) so my calling code looks like</p> <pre><code>return query .OrderBy("Customer.LastName DESC, Customer.FirstName") .Paginate(1,25, 2345) .ToArray(); </code></pre> <p>or I can invoke it using strongly typed expressions like this</p> <pre><code>return query .OrderByDescending(c=&gt;c.LastName) .ThenBy(c=&gt;c.FirstName) .Paginate(1,25,2345) .ToArray(); </code></pre> <p>Is this type of checking possible? I tired using <code>IOrderableQueryable&lt;T&gt;</code> in method signature but Dynamic Linq does not return <code>IOrderableQueryable</code> when you use OrderBy(string expression) so extension would not apply...</p> <h2>UPDATE</h2> <p>Using suggestion (pointed out by @GertArnold) the only workable solution was to inspect the expression tree. However, instead of making use of entire <code>ExpressionVisitor</code> I simplified my solution by requiring that Paginate method must be called just after <code>OrderBy</code> or <code>OrderByDescending</code>. This allowed me to check only current node in expression tree instead of searching the whole tree. So this is what I did:</p> <pre><code>// snip....class level private static readonly string[] PaginationPrerequisiteMehods = new[] { "OrderBy", "OrderByDescending" }; // snip Paginate method public static IQueryable&lt;T&gt; Paginate&lt;T&gt;(this IQueryable&lt;T&gt; query, int page, int pageSize = 50, int total = -1) { // require that either OrderBy or OrderByDescending was applied just before calling Paginate.... if (query.Expression.NodeType != ExpressionType.Call) { //TODO: logging -&gt; "You have to apply OrderBy() or OrderByDescending() just before calling Paginate()" return query; } var methodName = ((MethodCallExpression) query.Expression).Method.Name; if (!Array.Exists(PaginationPrerequisiteMehods, s =&gt; s.Equals(methodName, StringComparison.InvariantCulture))) { //TODO: logging -&gt; "You have to apply OrderBy() or OrderByDescending() just before calling Paginate()" return query; } page = (page &lt; 1) ? 1 : page; var limit = (pageSize &lt;= 0 || (total &gt;= 0 &amp;&amp; pageSize &gt; total)) ? 50 : pageSize; var skip = (page - 1)*limit; return query.Skip(skip).Take(limit); } </code></pre>
    singulars
    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