Преобразование оператора SQL CASE WHEN и оператора группы в LINQ

Как я могу написать в свободном синтаксисе linq оператор sql «случай, когда»?

select QueueItem, COUNT(*) as [Count],
SUM(CASE WHEN Queued = 0 THEN 1 ELSE 0 END) AS [Sent],
SUM(CASE WHEN Queued = 1 THEN 1 ELSE 0 END) AS Queued,
SUM(CASE WHEN Success = 1 THEN 1 ELSE 0 END) AS Exported,
SUM(CASE WHEN Success = 0 THEN 1 ELSE 0 END) AS Failed
from ExportQueue x
group by QueueItem

Есть ли какая-нибудь программа, которая может конвертировать SQL в LINQ? Линкпад может?


person JK.    schedule 03.01.2012    source источник
comment
В linq сделать это на удивление сложнее. В середине чего-то, но я вернусь через 30 минут и напишу, если у вас еще нет решения. Ключ в том, чтобы сделать ваш случай анонимным результатом, а затем вашей группой и суммой после него.   -  person Gats    schedule 03.01.2012
comment
Спасибо. Цель запроса, если это не ясно, состоит в том, чтобы сгруппировать по элементу очереди (продажа/кредит/покупка/и т. д.) и сообщить, сколько отправлено, сколько осталось в очереди, сколько было успешно и сколько не удалось   -  person JK.    schedule 03.01.2012
comment
Ага понял. Я хочу помочь, так как мне нравится, как вы используете суммы и падежи. Это тоже мой старый трюк, и я удивлен, что люди не используют его больше, потому что он очень быстрый. Вам нужно иметь в виду, что linq, очевидно, будет делать это намного медленнее. Я по-прежнему предпочитаю хранимые процедуры для сложных агрегатов, так как случаи левого соединения могут очень легко выйти из-под контроля, но этот должен быть в порядке.   -  person Gats    schedule 03.01.2012


Ответы (3)


Хорошо, что-то вроде этого. Мне нужно немного информации, чтобы быть уверенным, хотя

Немного в очереди? Это имеет значение для linq, а не для SQL. Я также не знаю ваших контекстных имен, но вы должны получить представление.

var query = Context.ExportQueues.Select(x => new { 
  QueueItem = x.QueueItem, 
  Sent = !x.Queued ? 1 : 0,
  Queued = x.Queued ? 1 : 0,
  Exported = x.Success ? 1 : 0,
  Failed = !x.Success ? 1 : 0 })
.GroupBy(x => x.QueueItem)
.Select(g => new { 
  QueueItem = g.Key,
  Sent = g.Sum(x => x.Sent),
  Queued = g.Sum(x => x.Queued),
  Exported = g.Sum(x => x.Exported),
  Failed = g.Sum(x => x.Failed)
}).ToList();

РЕДАКТИРОВАНИЕ Вы также можете комбинировать их, выполнив проверку на лету в запросе. Я всегда склонен сначала записывать его, как указано выше, когда работаю над ним, хотя более сложные агрегаты могут быть немного сложными для отладки, если есть ошибки:

var query = Context.ExportQueues
.GroupBy(x => x.QueueItem)
.Select(g => new { 
  QueueItem = g.Key,
  Sent = g.Sum(x => !x.Queued ? 1 : 0),
  Queued = g.Sum(x => x.Queued ? 1 : 0),
  Exported = g.Sum(x => x.Success ? 1 : 0),
  Failed = g.Sum(x => !x.Success ? 1 : 0 )
}).ToList();
person Gats    schedule 03.01.2012
comment
На самом деле это битовые поля с нулевым значением, поэтому я изменил ваш Sent = !x.Queued ? 1 : 0 на Sent = x.Queued != true ? 1 : 0 и т. д. Но группировка не работает, она возвращает одну группу для каждой строки. - person JK.; 03.01.2012
comment
Я сделал ошибку в QueueItem = x. Отредактированная версия должна быть лучше. ЭлементОчереди = x.ЭлементОчереди, - person Gats; 03.01.2012
comment
Да, я только что вернулся, чтобы сказать, что x должен был быть x.QueueItem :) - person JK.; 03.01.2012
comment
Эта последняя строка должна быть Failed = g.Sum(x => !x.Success ? 1 : 0 ) для подсчета количества сбоев, !x.Success ? 0 : 1 подсчитывает количество не сбоев, то есть успехов :) - person JK.; 03.01.2012
comment
хе-хе получил это задом наперед. Агрегаты Linq, написанные вслепую, за 5 минут без vs могут быть трюком :D Отредактировал его так, как он должен быть. - person Gats; 03.01.2012

В качестве альтернативы решению Gatts вы можете сделать что-то вроде

var query = Context.ExportQueues.
.GroupBy(x => x.QueueItem)
.Select(g => new { 
  QueueItem = g.Key,
  Sent = g.Count(x=>!x.Queued),
  Queued = g.Count(x => x.Queued),
  Exported = g.Count(x => x.Success),
  Failed = g.Count(x => !x.Failed)
}).ToList();
person Muhammad Adeel Zahid    schedule 03.01.2012
comment
Это тоже должно работать, хотя я думаю, что это может привести к созданию большего количества подзапросов. Я собираюсь попробовать их обоих и рассказать о них, когда у меня будет время, так как это интересно. - person Gats; 03.01.2012

На самом деле это довольно многословно писать с использованием LINQ. Что вам нужно сделать, так это сначала сгруппировать, а затем использовать лямбда-выражения для обработки агрегации. Итак, что-то вроде:

from eq in ExportQueue
group eq by new {
    eq.QueueItem
} into temp
select new {
    temp.Key.QueueItem,
    Agg1 = temp.Sum(n => n.Queued == 0 ? 1 : 0),
    Agg2 = temp.Sum(n => n.Queued == 1 ? 1 : 0)
}

И так далее, LinqPad будет действительно полезен при попытке заставить это работать.

person daz-fuller    schedule 03.01.2012