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
}
}