Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Skip ThenBy on nullable objects

I have a query which should be ordered like that:

var list = new List<MonthClosureViewModel>();
var orderedList = list
    .OrderByDescending(x => x.Project)
    .ThenByDescending(x => x.ChargeLine)
    .ThenByDescending(x => x.DomesticSite) //<- x.DomesticSite might be null sometimes
    .ThenByDescending(x => x.ChargeSite)   //<- x.ChargeSite   might be null sometimes
    .ThenByDescending(x => x.RateGroup)
    .ThenByDescending(x => x.ApprovedHrs)
    .ThenByDescending(x => x.NotApprovedHrs);

public class MonthClosureViewModel
{
    public Project Project { get; set; }
    public ChargeLine ChargeLine { get; set; }
    public Site DomesticSite { get; set; }
    public Site ChargeSite { get; set; }
    public RateGroup RateGroup { get; set; }
    public decimal Rate { get; set; }
    public decimal ApprovedHrs { get; set; }
    public decimal NotApprovedHrs { get; set; }
}

But if any object is null (totally by design) this query fails. How can I put null values at the end or skip ordering if object is null?

ADDED: as @LasseV.Karlsen mentioned I might have ANOTHER problem. I really got ArgumentNullException, but the reason was not behind some object were null (I saw it in debugger and falsely thought that it was my problem). The real reason was as @RaphaëlAlthaus mentioned that I didn't implement IComparable<> at ANY of my classes in MonthClosureViewModel...

After I've done it everything start working as intended even if object is null

like image 434
Szer Avatar asked May 22 '15 10:05

Szer


2 Answers

You try to order by complex properties, which is (as you mentionned) the real problem.

To make it possible you'll have to, either

  1. implement IComparable<T> on your classes

  2. use other overloads of OrderBy / OrderByDescending, which take also an IComparer<TKey> as argument (msdn for the OrderBy overload)

  3. Use a simple property of the complex property in your order by clause (with null check. In this case, the null check becomes necessary to avoid a Null Reference Exception) :

For example :

.OrderByDescending(x => x.Project == null ? string.Empty : x.Project.Name)
like image 115
Raphaël Althaus Avatar answered Nov 10 '22 12:11

Raphaël Althaus


You'll need to define defaultSite and defaultChargeSite to be either smaller or larger than all the other objects in their class

var list = new List<MonthClosureViewModel>();
var orderedList = list
     .Where(x => x != null);
    .OrderByDescending(x => x.Project)
    .ThenByDescending(x => x.ChargeLine)
    .ThenByDescending(x => x.DomesticSite==null?defaultSite:x.DomesticSite) //<- x.DomesticSite might be null sometimes
    .ThenByDescending(x => x.ChargeSite==null?defaultChargeSite:x.ChargeSite)   //<- x.ChargeSite   might be null sometimes
    .ThenByDescending(x => x.RateGroup)
    .ThenByDescending(x => x.ApprovedHrs)
    .ThenByDescending(x => x.NotApprovedHrs);
like image 3
Uri Goren Avatar answered Nov 10 '22 11:11

Uri Goren