LINQ с помощью Max () для выбора одной строки


Я использую LINQ на IQueryable, возвращенном из NHibernate, и мне нужно выбрать строку с максимальным значением(ами) в нескольких полях.

я упростил бит,который я придерживаюсь. Мне нужно выбрать одну строку из моей таблицы с максимальным значением в одном поле.

var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }

from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u

Это неправильно, но я не могу выработать правильную форму.

кстати, то, что я на самом деле пытаюсь достичь, примерно так:

var clientAddress = this.repository.GetAll()
    .GroupBy(a => a)
    .SelectMany(
            g =>
            g.Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.AddressReference == g.Max(x => x.AddressReference) && 
                a.StartDate == g.Max(x => x.StartDate)))
    .SingleOrDefault();

Я начал с выше лямбда, но я использую LINQPad, чтобы попытаться разработать синтаксис для выбора Max().

обновление

удаление GroupBy было ключевым.

var all = this.repository.GetAll();

var address = all
            .Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.StartDate == all.Max(x => x.StartDate) &&
                a.AddressReference == all.Max(x => x.AddressReference))
            .SingleOrDefault();
5 77

5 ответов:

Я не понимаю, почему вы группировку здесь.

попробуйте это:

var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);

альтернативный подход, который будет итерировать table только один раз будет это:

var result = table.OrderByDescending(x => x.Status).First();

это полезно, если table это IEnumerable<T> чего нет в памяти или что вычисляется на лету.

вы можете сгруппировать по статусу и выбрать строку из самой большой группы:

table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();

первый First() получает первую группу (набор строк с наибольшим статусом); вторая First() получает первую строчку в этой группе.
Если статус всегда unqiue, вы можете заменить второй First() С Single().

вы также можете сделать:

(from u in table
orderby u.Status descending
select u).Take(1);

обращаясь к первому вопросу, если вам нужно занять несколько строк, сгруппированных по определенным критериям, с другой столбец с максимальным значением вы можете сделать что-то вроде этого:

var query =
    from u1 in table
    join u2 in (
        from u in table
        group u by u.GroupId into g
        select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
    ) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
    select u1;

просто в одну строку:

var result = table.First(x => x.Status == table.Max(y => y.Status));

обратите внимание, что есть два действия. внутренние действия для нахождения максимального значения, внешние действия для получения желаемого объекта.