3

I have a table that I am writing some C# selenium automation for and need some help using Dynamic Linq. Let's say I have a basic AcctNum, AcctDate and AcctName record and each field can be sorted by the user. They could choose AcctNum (asc), AcctDate(asc) and finally AcctName (asc).

That would be:

 var sortedCode = records.OrderBy(r => r.AcctNum)
                         .ThenBy(r => r.AcctDate)
                         .ThenBy(r => r.AcctName)
                         .ToList();

However the user could also choose AcctNum (desc), AcctDate(asc) and finally AcctName (desc).

What I would like to do is use Dynamic Linq and make each sort order a variable.

So something like:

 //passed in values:
 var varAcctNumOrd = "desc";
 var varDateOrd = "asc";
 var varAcctOrd = "desc";

 var sortedCode = records.OrderBy(r => r.AcctNum, varAcctNumOrd)
                         .ThenBy(r => r.AcctDate, varDateOrd)
                         .ThenBy(r => r.AcctNum, varAcctOrd)
                         .ToList();

Is this possible?

Dazed
  • 1,527
  • 1
  • 13
  • 25
  • Are you asking for dynamic direction (ascending/descending) or the fields also are dynamic? And btw, so called Dynamic LINQ (`System.Linq.Dynamic`) works with strings. – Ivan Stoev Sep 27 '16 at 20:15
  • Hey Ivan. The test case will pass a variable for ascending or descending order for each field. I just need to pass each of those variables to the sort order so I van validate the sorts are working correctly in the UI. – Dazed Sep 27 '16 at 20:17
  • And what is the **type** of the `records` variable - `IQueryable` or `IEnumerable`? – Ivan Stoev Sep 27 '16 at 20:24
  • Right now records is IEnumerable – Dazed Sep 27 '16 at 20:33

3 Answers3

5

If I understand correctly, the following simple custom extension methods should do the job:

public static class LinqExtensions
{
    public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        bool ascending)
    {
        return ascending ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
    }

    public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(
        this IOrderedEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        bool ascending)
    {
        return ascending ? source.ThenBy(keySelector) : source.ThenByDescending(keySelector);
    }

    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(
        this IQueryable<TSource> source,
        Expression<Func<TSource, TKey>> keySelector,
        bool ascending)
    {
        return ascending ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
    }

    public static IOrderedQueryable<TSource> ThenBy<TSource, TKey>(
        this IOrderedQueryable<TSource> source,
        Expression<Func<TSource, TKey>> keySelector,
        bool ascending)
    {
        return ascending ? source.ThenBy(keySelector) : source.ThenByDescending(keySelector);
    }
}

And the usage will be:

//passed in values:
var varAcctNumOrd = "desc";
var varDateOrd = "asc";
var varAcctOrd = "desc";

var sortedCode = records.OrderBy(r => r.AcctNum, varAcctNumOrd != "desc")
                        .ThenBy(r => r.AcctDate, varDateOrd != "desc")
                        .ThenBy(r => r.AcctNum, varAcctOrd != "desc")
                        .ToList();
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Thanks Ivan and everyone else. I appreciate the quick replies. I will take a look and see if I can digest all of this :). – Dazed Sep 27 '16 at 20:41
  • Ivan I think the first static needs to be public static IOrderedEnumerable OrderByWithDirection (this IEnumerable source, – Dazed Sep 28 '16 at 20:40
  • @Dazed Right, thank you! (and sorry, I did it for `IQueryable`, then copy/pasted/adjusted for `IEnumerable` and missed that). – Ivan Stoev Sep 28 '16 at 21:11
  • Appreciate the help on this one. Worked well. – Dazed Sep 30 '16 at 16:36
0

If I understand your question, you want to handle a dynamic ordering for your collection according each column and direction (i.e. AcctNum desc)

I'm agree with Ivan Stoev, that kind of linq works with strings not with typed classes.

You can solve this issue using AsQueryable() solution.

H. Herzl
  • 3,030
  • 1
  • 14
  • 19
0

Until the ToList is called one is building a query thanks to the IQueryable interface. Simply have some Booleans to determine direction and do the ordering as such:

var recordsToSort = records.AsQueryable();

if (isByAcctNum)
{
   recordsToSort = recordsToSort.OrderBy(r => r.AcctNum);

   if (isByDate)
      recordsToSort =  recorsToSort.ThenBy(r => r.AcctDate)

   ....
}
else
{
    ....

}

return recordsToSort.ToList()

You need to put in the precedence logic of the primary sort for the first OrderBy call then each secondary ThenBy calls. Which I leave up to you, I don't know the data.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122