2

I have a SQL table with over 800k records that need to be displayed on the web in pages of 25 results. I need to be able to search and sort these results from the table, but because the table is so large I cannot pull all the results to an IEnumerable before filtering/sorting (I was doing this before and it worked, but it is now incredibly slow doing the initial pull).

I've figured out the search, but the sort is really messing me up. I've spent hours researching it, but can't find any solutions that work before the .Skip().Take().

I need to be able to do something like this:

string sortField = "Name"; //just for example
string sortDirection = "descending"; //also for example
List<People> = (from s in db.People
                orderby sortField sortDirection
                select s).Skip((page - 1) * pageSize).Take(pageSize).ToList();

The sortable columns in People can be DateTime, ints, or strings, so my attempts to do something like

orderby (
    currentSort == "Name" ? s.Name : 
    currentSort = "SignUpDate" ? s.SignupDate : s.Id
)

were in vain, as the program complains about mixing types.

Is there anything that can be done to make this work? Thanks in advance for any help or leads!

Zach
  • 33
  • 4

1 Answers1

2

You can use the following custom extension method, which builds OrderBy(Descending) call dynamically using the System.Linq.Expressions.Expression class (similar to How to use a string to create a EF order by expression?):

public static partial class QueryableExtensions
{
    public static IOrderedQueryable<T> OrderByMember<T>(this IQueryable<T> source, string memberPath, bool descending)
    {
        var parameter = Expression.Parameter(typeof(T), "item");
        var member = memberPath.Split('.')
            .Aggregate((Expression)parameter, Expression.PropertyOrField);
        var keySelector = Expression.Lambda(member, parameter);
        var methodCall = Expression.Call(
            typeof(Queryable), descending ? "OrderByDescending" : "OrderBy", 
            new[] { parameter.Type, member.Type },
            source.Expression, Expression.Quote(keySelector));
        return (IOrderedQueryable<T>)source.Provider.CreateQuery(methodCall);
    }
}

like this:

var people = db.People
    .OrderByMember(sortField, sortDirection == "descending")
    .Skip((page - 1) * pageSize).Take(pageSize)
    .ToList();
Community
  • 1
  • 1
Ivan Stoev
  • 159,890
  • 9
  • 211
  • 258
  • 1
    When you notice a question is a duplicate you should be voting to close it as such, not just copy-pasting your answer to the duplicate question. – Servy Dec 09 '16 at 21:20
  • @Servy Agreed. I do that usually, but here decided that it's a variation and the other answer does not apply directly. But you are right, I should have searched for other duplicates. – Ivan Stoev Dec 09 '16 at 21:23
  • 2
    @Servy I really did look around for a few hours trying every solution I could find with no luck. Ivan, thank you so much! This worked brilliantly! – Zach Dec 09 '16 at 21:25
  • @Zach It's not exactly [hard to find](https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=linq+order+by+string), but that's not really the point. The point is that Ivan knows better than to copy-paste his answer from a duplicate to another question instead of marking it as a duplicate. That you didn't find a duplicate is somewhat understandable, that he knew it was a duplicate and ignored the fact is quite different. – Servy Dec 09 '16 at 21:31
  • 1
    @Zach You are welcome mate, glad it helped :) – Ivan Stoev Dec 10 '16 at 01:26
  • @IvanStoev please can you kindly extend this answer to include a dynamic where clause filter as well. Thanks! – Charles Okwuagwu Sep 19 '17 at 17:09
  • 1
    @CharlesOkwuagwu The dynamic `Where` is quite different, mainly the signature (parameters) and the operations supported (e.g. `name`, `operator`, `value` etc.). [Dynamic LINQ](https://github.com/kahanu/System.Linq.Dynamic) provides a full solution for both problems, but if you want a customized method for your need, you might post a question and I'll be happy to look at it. Cheers. – Ivan Stoev Sep 19 '17 at 17:38
  • @IvanStoev would it be similar to your previous post? What i'm looking for in particular is` Where field LIKE '%abc%' ` https://stackoverflow.com/questions/39182903/how-to-construct-where-expression-dynamically-in-entity-framework – Charles Okwuagwu Sep 19 '17 at 17:44
  • @CharlesOkwuagwu Yes, that's one of the variations - dynamic `Where` with equality check, e.g. `Where(x => x.Prop == val)`. But it needs to be extended if you need `!=`, `>`, `Contains` etc. conditions. – Ivan Stoev Sep 19 '17 at 17:47
  • @IvanStoev Thanks https://stackoverflow.com/questions/46306955/how-to-construct-a-dynamic-where-filter-in-ef-core-to-handle-equals-like-gt-l – Charles Okwuagwu Sep 19 '17 at 17:55