Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ OrderBy different field type depending on IF statement

Tags:

c#

sorting

linq

I'm trying to sort some data that can be in one of the following (inferred) states (in this order):

  • live (valid StartDate, null EndDate);
  • draft (null StartDate);
  • ended (valid EndDate).

I've inherited the following syntax on a IQueryable:

iQueryableData
    .OrderBy(t => t.StartDate == null ? 1 : (t.EndDate == null ? 0 : 2))
    .ThenByDescending(t => t.StartDate)
    .ThenBy(t => t.PartnerId)

And that is fine, since it sorts on one of the first 3 columns of the table, depending on some IF statements.

Now I need to rewrite that to work in memory (so just LINQ, no IQueryable), on a different (but similar) model. Here's what the above query will roughly translate to:

data
    .OrderBy(t => t.StartDate == null 
                      ? t.EndDate // DateTime
                      : (t.EndDate == null 
                            ? t.Id // integer
                            : t.Name // string
                        )
            )

This obviously fails to compile, because

CS0173 C# Type of conditional expression cannot be determined because there is no implicit conversion between 'int' and 'string'

Presumably, I could keep sorting by an integer, but I've no idea what the numbers would refer to in this case (the order of the property as written inside the class? The sorted by name order of the same thing?).

Unfortunately, all questions I've found related to mine are ordering based on an IF statement that's relying on an external value (not inside the data).

like image 982
Alexandru Marculescu Avatar asked Oct 17 '22 22:10

Alexandru Marculescu


1 Answers

Use the ThenBy extension. This ensures that the previous order is maintained while applying a new order criteria. For each specific case return the desired property to participate in order (Name, Id, EndDate) so each group in the set will be sorted by these values. Use some constant value for the other items that do not meet the original criteria so their order remains unchanged by the current ThenBy.

    items
    //sort by live, draft and ended
 .OrderBy(t => t.StartDate == null ? 1 : (t.EndDate == null ? 0 : 2)) 
        //keep the live, draft and ended sort,
        //and for the live items  apply only a sort by ID, 
        //but let the other items in the previous order (live, draft and ended) 
        //by returning the same value for each (zero or null)
    .ThenBy( t=> t.StartDate != null && t.EndDate == null ? t.ID : 0) 
            //the same
            //keep the sort by live, draft, ended and now by ID for live ones only
            //but for the draft items sort them by EndDate
            //leave the others unaffected by this sort
        .ThenBy( t=> t.StartDate == null && t.EndDate != null ? t.EndDate : default(DateTime?))
                //same - sort ended items by name
            .ThenBy( t=> t.StartDate != null && t.EndDate != null ? t.Name : null)
like image 77
Adrian Iftode Avatar answered Nov 02 '22 11:11

Adrian Iftode