OrderBy
The OrderBy feature in specifications functions just like LINQ’s OrderBy method. It accepts an Expression<Func<TSource, TKey>> and is used to define the primary sort order for the query results.
public class CustomerSpec : Specification<Customer>
{
public CustomerSpec()
{
Query.OrderBy(x => x.Name);
}
}
To sort in descending order, use OrderByDescending.
Query.OrderByDescending(x => x.Name);
For multi-level sorting, use ThenBy and ThenByDescending.
Query.OrderByDescending(x => x.Name)
.ThenByDescending(x => x.Id)
.ThenBy(x => x.DateCreated);
Conditional Overloads
All ordering methods support an overload that accepts a bool condition. If the condition evaluates to false, the ordering expression is ignored. This is useful for building dynamic or optional sorting logic.
public class CustomerSpec : Specification<Customer>
{
// Instead of having this
public CustomerSpec(bool shouldOrder)
{
if (shouldOrder)
{
Query.OrderBy(x => x.Name);
}
}
// Users can do this
public CustomerSpec(bool shouldOrder)
{
Query.OrderBy(x => x.Name, shouldOrder);
}
}
Because ordering supports method chaining, conditional evaluation affects the entire chain. If a parent ordering method is not applied (due to a false condition), any chained ThenBy or ThenByDescending calls are automatically discarded.
public class CustomerSpec : Specification<Customer>
{
public CustomerSpec()
{
Query.OrderBy(x => x.Id, false)
.ThenBy(x => x.Name); // since the parent is not added, this also will be discarded
}
}
public class CustomerSpec : Specification<Customer>
{
public CustomerSpec()
{
Query.OrderBy(x => x.Id) // it will be added
.ThenBy(x => x.Name, false) // it won't be added
.ThenByDescending(x => x.Email); // since the parent is not added, this also will be discarded
}
}