2016-10-13 3 views
2

У меня есть этот запрос LINQ:заказа пользователя, а затем выберите максимальную дату

ArrayList arr = new ArrayList(); 
var data = conn.SCOT_DADOS.OrderByDescending(x => x.DATE) 
          .GroupBy(r => r.USER) 
          .ToList(); 
foreach (var item in data) 
{ 
    var itemdata = item.Where(r => r.DATE == item.Max(s => s.DATE)); 

    var name = svc.GetUserName(itemdata.Select(r => r.USER).First().ToString()); 
    var value = itemdata.Select(r => r.VALUE).First(); 
    var date = itemdata.Select(r => r.DATE).First().ToString("dd/MM/yyyy HH:mm:ss"); 

    arr.Add(new{ NAME = name, DATE = date, VALUE = value}); 
} 

Этот код даст мне последний результат, DATE для каждого USER.

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

Есть ли способ получить только последние данные в запросе LINQ, поэтому мне не нужно принимать все пользовательские данные каждый раз?


Я попытался это:

var data = conn.SCOT_DADOS.OrderByDescending(x => x.DATE) 
          .GroupBy(r => r.USER) 
          .First() 
          .ToList(); 

А затем обрабатывают item как объект, вместо запуска выбирает на нем.

Он дал мне все данные для отдельного пользователя, чего я не хочу.

Что можно сделать?


Edit 1:

Я получаю эту ошибку при попытке поменять OrderByDescending и GroupBy: CS1061

Error 'IGrouping' не содержит определение 'DATE' и нет метод расширения «DATE», принимающий первый аргумент типа «IGrouping», может быть найден ( у вас отсутствует директива using или ссылка на сборку?)


Edit 2:

Это некоторые выборочные данные (имена столбцов не то же самое, потому что я перевел их на вопрос):

enter image description here

Из приведенных данных , У меня были бы результаты:

enter image description here

+0

Попробуйте поменять порядок и группу. –

+0

Я получаю сообщение об ошибке. Я добавлю к вопросу. – Phiter

+0

@Phiter Fernandes - Пожалуйста, объясните, что вы имеете в виду. Добавление ввода ввода и данных результата поможет –

ответ

2

Если комбинация (USER, DATE) пара уникальна (который, кажется, тот случай, когда, глядя на образец данных), то требование может быть урезано до

возвращения каждой записи, если нет других записей с тем же USER и позже DATE

, которые могут быть переведены на фо llowing Запрос LINQ:

var result = conn.SCOT_DADOS 
    .Where(r => !conn.SCOT_DADOS.Any(r2 => r2.USER == r.USER && r2.Date > r.Date)) 
    // end of Db Query 
    .AsEnumerable() 
    .Select(r => new 
    { 
     Name = svc.GetUserName(r.User), 
     Value = r.Value, 
     Date = r.Date.ToString("dd/MM/yyyy HH:mm:ss") 
    }).ToList(); 
+0

Я мог бы сделать это, используя первичный ключ. Последняя дата также будет последней идентификацией. Было бы безопаснее? – Phiter

+0

Ну, если вы можете положиться на него (я думаю, это автоматический номер). Я бы предпочел включить его как проверку безопасности - например, r2 => r2.USER == r.USER && (r2.Date> r.Date || (r2.Date == r.Date && r2.Id> r. Id)) ' –

+0

Это ничего не возвращает – Phiter

2

Я немного смущен, но от ваших попыток с First() думаю, вы имеете в виду это:

conn.SCOT_DADOS.GroupBy(item => item.User) 
       .Select(grp => grp.OrderByDescending(i => t.Date).First()); 

Это будет получать для каждогоUserтолько последняя запись его


причина только свопинга GroupBy и OrderByDescending не достаточно, и что вам нужно Select, так это то, что как только вы сгруппировали эти данные, ваш перечислимый IEnumerable<IGrouping<User,YourType>>. Каждый IGrouping на самом деле представляет собой коллекцию, поэтому вам нужно, чтобы Select только 1 элемент, который вы хотите от него.

Другой способ заключается в замене Select с:

.SelectMany(grp => grp.OrderByDescending(i => t.Date).Take(1)) 

ИМО первый чище, но второй является в том случае, нужно для каждого пользователя N первых пунктов


На запрос выше, вы также можете добавить то, что у вас есть в петле:

conn.SCOT_DADOS.GroupBy(item => item.User) 
      .Select(grp => grp.OrderByDescending(i => t.Date).First()) 
      .AsEnumerable() 
      .Select(item => new { 
       Name = svc.GetUserName(item.User), 
       Value = item.Value, 
       Date = item.Date.ToString("dd/MM/yyyy HH:mm:ss") 
      }).ToList(); 

Использование AsEnumerable() является для вызова запроса будет выполняться в базе данных до последнего Select(), который использует GetUserName метод, который не будет известен в базе данных Oracle

IMO, представляющий DateTime, как строка не хороший способ ..


Update - ошибка вы получите:

Oracle 11.2.0.3.0 не поддерживает применять

кажется, что в этой версии Oracle не поддерживает GroupBy с Select через LINQ. См. Linq to Entities Group By (OUTER APPLY) “oracle 11.2.0.3.0 does not support apply”. Один ответ там рекомендовал создать представление в базе данных для этого, а затем использовать linq для выбора над этим представлением. Это то, что я бы на

+1

Я сейчас пытаюсь ваше решение. Я представляю DateTime как строку, потому что это будет показано пользователю. – Phiter

+0

Это дало мне * Метод «Первый» может использоваться только как конечная операция запроса. Вместо этого рассмотрите возможность использования метода FirstOrDefault в этом экземпляре. * – Phiter

+0

Кроме того, мне пришлось изменить на 'OrderByDescending (i => i.Date)' – Phiter

0

Попробуйте

conn.SCOT_DADOS.GroupBy(x => x.User).Select(x => new 
       { 
        User = x.Key, 
        Date = list.Where(y => y.User == x.Key).Max(y => y.Date) 
       }); 
Смежные вопросы