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().

UPDATE

Удаление 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();

Ответ 1

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

Попробуйте следующее:

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>, который отсутствует в памяти или который вычисляется на лету.

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

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;

Ответ 5

Просто в одной строке:

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

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