Any suggestions on how to make this LINQ query more efficient? I recently created the formattedDate variable as previously I was calling the GetDateInFormat multiple times.
if (customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom" && ol.ActualDate != null)
.Any())
{
var date = customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.ActualDate)
.FirstOrDefault(d => d.DateTypeId == "OrderPickUpFrom" && d.ActualDate != null)
.ActualDate;
if (date != null)
{
var formattedDate = _dateHelper.GetDateInFormat("DD/MM/YYYY", date);
order.ArriveDate = formattedDate;
order.EarliestShipDate = formattedDate;
order.EarliestDeliveryDate = formattedDate;
order.EarliestApptTime = _dateHelper.GetDateInFormat("HHMM", date);
}
}
The customerOrder is a customer Order class.
public class Order
{
public Order();
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public OrderLine();
public List<OrderDate> OrderDates { get; set; }
}
public class OrderDate
{
public OrderDate();
public DateTimeOffset? ActualDate { get; set; }
public string DateTypeId { get; set; }
}
>Solution :
Well,
-
First of all let’s get rid of two Linq queries in a row:
Any()
and thenFirstOrDefault
. We can execute justFirstOrDefault
(or its equivalent) and if we getnull
we’ll know thatAny
returnsfalse
(i.e. we have no items). -
Second, with
OrderBy
we sort the entire enumerable and then we drop all but one item. We are wasting resources.Aggregate
is more economic way: we have no need to sort but scan the enumeration and return eithernull
or smallestActualDate
.
Code:
var date = customerOrder
.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom" && ol.ActualDate != null)
.Select(ol => ol.ActualDate)
.Aggregate((DateTimeOffset?) null,
(s, a) => !s.HasValue || s.Value > a ? a : s);
if (date.HasValue) {
var formattedDate = _dateHelper.GetDateInFormat("DD/MM/YYYY", date);
order.ArriveDate = formattedDate;
order.EarliestShipDate = formattedDate;
order.EarliestDeliveryDate = formattedDate;
order.EarliestApptTime = _dateHelper.GetDateInFormat("HHMM", date);
}