#c# #linq
Вопрос:
У меня есть запрос LINQ, который возвращает значения, которые я хочу, из таблицы Person, двух связанных дочерних таблиц (Агентские и кадровые сертификаты) и связанной таблицы внуков (тип сертификата). Это работает нормально. Вот запрос LINQ на данный момент (я использую .NET 4.5.2 и EF 6):
using (var ctx = new AppEntities())
{
People = ctx.People.AsNoTracking().Where(p => p.Inactive == false)
.Include(p => p.Agency)
.Include(p => p.PersonnelCertifications.Select(pc => pc.CertificationType))
.Where(p => p.PersonnelCertifications.Any(pc => pc.CertificationType.CertType == "Operator"))
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName)
.ToList();
}
(Люди — это список типов людей.) Однако теперь у меня есть новое требование. В таблице PersonnelCertifications есть столбец с именем CertExpirationDate
. Возможно, что может быть 3 записи о персонале, связанные с одним человеком. Например, самым старым может быть 12 сентября 2015 года. Следующий может быть 20 апреля 2021 года. Последнее может быть 12 февраля 2022 года для какого-то человека. При выполнении запроса мне нужна только запись PersonnelCertifications за 12 февраля 2022 года. Как я могу изменить приведенный выше запрос LINQ, чтобы получить максимальную дату сертификации персонала для каждого человека?
Ответ №1:
Простым решением было бы просто загрузить все PersonnelCertifications
для a Person
из базы данных, а затем отфильтровать самое последнее в памяти, т. е.
foreach(person in People) {
person.PersonnelCertifications = person.PersonnelCertifications.Where(pc => pc.CertExpirationDate == person.PersonnelCertifications.Max(pc => pc.CertExpirationDate ) )
}
другим вариантом было бы спроецировать сущности в пользовательский класс DTO. Таким образом, вам не нужно загружать дополнительные PersonnelCertifications
данные из базы данных, только самые последние, т. е.
public class PersonViewModel {
public string Name {get; set;}
public string Age {get; set;}
public IEnumerable<PersonalCertificationViewModel> PersonnelCertifications {get; set;}
}
public class PersonalCertificationViewModel {
public string Name {get; set;}
public DateTime ExpirationDate {get; set;}
}
People = ctx.People.AsNoTracking().Where(p => p.Inactive == false)
.Include(p => p.Agency)
.Include(p => p.PersonnelCertifications.Select(pc => pc.CertificationType))
.Where(p => p.PersonnelCertifications.Any(pc => pc.CertificationType.CertType == "Operator"))
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName)
.Select(p => new PersonViewModel {
Name = p.Name,
Age = p.Age,
PersonnelCertifications = p.PersonnelCertifications.Where(pc => pc.CertExpirationDate == p.PersonnelCertifications.Max(pc => pc.CertExpirationDate))
.Select(pc => new PersonnelCertifications { Name = pc.Name, ExpirationDate = pc.ExpirationDate })
}).ToList()
Комментарии:
1. Антон, я решил сначала воспользоваться простым решением, которое ты дал. Просто к вашему сведению, я обнаружил, что мне пришлось использовать
ToList()
для присвоения отфильтрованного значенияperson.PersonnelCertifications
.