Мне кажется, что вы выполняете циклы select-where-order один раз для каждого Cycle1 - Cycle5.
Кроме того, вам нужно сделать что-то сложное, если результат FirstOrDefault равен нулю.
Я бы посоветовал использовать больше Selects для оптимизации вашего кода.
Меньшими шагами:
var selectedSitesAndCycles = dbContext.Sites
// keep only those sites that ...
.Where(site => site.YardID == yardId
&& site.SiteTypeID == siteTypeId
&& site.Season.SeasonYear == DateTime.Now.Year)
// order the remaining sites in ascending order by name
.OrderBy(site => site.Community.Name)
// from every ordered site, get some properties and a list of 5 cycles:
.Select(site => new
{
Pin = site.Pin,
Community = site.Community.Name,
Neighbourhood = site.Neighbourhood,
Address = site.StreetAddress,
Area = site.Area,
Notes = site.Notes,
ClosedDates = site.JobCards
.Where(job => job.OperationID == 1)
.OrderByDescending(job => job.ClosedDate.HasValue)
.ThenBy(job => job.ClosedDate)
.Select(job => Date = job.ClosedDate)
.Take(5)
.ToList(),
});
Обратите внимание, что запрос еще не выполнен. Я беру всего 5 циклов. Я не использовал ключевое слово new при выборе ClosedDate. Следовательно, CycleClosedDates - это List<DateTime?>
.
Другими словами: каждый элемент CycleClosedDates является DateTime, допускающим значение NULL. Если вы возьмете FirstOrDefault
, вы получите либо первое значение DateTime, допускающее значение NULL, которое может быть DateTime или NULL, либо вы получите (DateTime?) NULL, если CycleClosedDates недостаточно.
Давайте рассмотрим случай, когда на сайте есть только три JobCard:
JobCard[0] is closed and has ClosedDate 2020-03-10
JobCard[1] is not closed yet. ClosedDate isn (DateTime?)null
JobCard[3] is closed and has ClosedDate 2020-03-20
// There is no JobCard[4] [5]
Результатом будет List<DateTime?>
длиной 3, где элемент [1] не имеет значения. Результатом Skip(1).FirstOrDefault()
будет DateTime без значения, допускающий значение NULL.
Приятно то, что Skip(4).FirstOrDefault()
также будет DateTime с нулевым значением без значения, даже если не существует 5 JobCard
Давайте продолжим с дополнительным Select для создания ваших пяти свойств:
.Select(site => new
{
Pin = site.Pin,
Community = site.Community.Name,
Neighbourhood = site.Neighbourhood,
Address = site.StreetAddress,
Area = site.Area,
Notes = site.Notes,
Cycle1 = site.CycleClosedDates.FirstOrDefault(),
Cycle2 = site.CycleClosedDates.Skip(1).FirstOrDefault(),
Cycle3 = site.CycleClosedDates.Skip(2).FirstOrDefault(),
...
})
Обратите внимание, что CycleClosedDates будет заказан только один раз. Поскольку CycleClosedDates уже является List<DateTime?>
, кажется немного излишним создавать отдельные свойства вместо одного списка длиной пять. Учтите, что при втором выборе
.Select(site => new
{
Pin = site.Pin,
Community = site.Community.Name,
...
CycleClosedDates = new List[]
{
site.CycleClosedDates.FirstOrDefault(),
site.CycleClosedDates.Skip(1).FirstOrDefault(),
site.CycleClosedDates.Skip(2).FirstOrDefault(),
...
},
};
или после первого выбора:
// move the selected data to local process
.AsEnumerable()
// 2nd select:
.Select(site => new
{
Pin = site.Pin,
Community = site.Community.Name,
...
CycleClosedDates = site.CycleClosedDates
.Concat(Enumerable.Repeat( (DateTime?)null, 5)
.Take(5)
.ToList();
Таким образом, вы уверены, что ваш CycleClosedDates имеет ровно пять значений DateTimes, допускающих значение NULL, даже если в все.