2012-02-13 4 views
1

Скажет, у меня есть сводная таблица, как это:Как выбрать совокупность нескольких столбцов (без группы)?

AcitivityCache 
(
    pkId (bigint, PK), 
    Date (DateTime), 
    OfficeId (int, FK) 
    TransactionCount (int), 
    RejectCount (int), 
    InvitationCount (int), 
    RequestCount (int) 
    ... 
    --more counts here-- 
    ... 
) 

Теперь мне нужно получить общее количество отсчетов в течение определенного периода времени (без группировки по должности, просто суммирует), которые я могу сделать с SQL, как это:

SELECT SUM(TransactionCount) as TotalTxCount, SUM(RejectCount) as TotalRejectCount, ... 
FROM ActivityCache 
WHERE [Date] between '2011-02-01' and '2012-02-01' 

Как я могу достичь этого с помощью linq? Большинство решений, которые я видел до сих пор, имеют некоторую группировку. Но для этого случая мне не нужна группировка, просто итоги. Я могу сделать вот так:

DateTime dateFrom, toDate; // initialized later 
... 
var q = dbContext.ActivityCaches 
       .Where(a=> a.Date > fromDate && a.Date <= toDate) 
       .GroupBy(a=> 1) 
       .Select(g=> new 
          { 
           TotalTransactionCount = g.Sum(a => a.TransactionCount), 
           TotalRejectCount = g.Sum(a => a.RejectCount), 
           ... 
           ... 
          }); 

Или, я могу сначала получить столбцы, а затем взять сумму программно. Или, я могу использовать SP (как в данном случае). Любые лучшие идеи (без группы)?

PS: Я не смогу изменить БД Schema

+1

Ну, T-SQL является * неявно * делает операцию группировки, это просто, что все записи в одной и той же группе, что то же самое, что вы делаете с вашим 'GroupBy (a => 1) '. Есть ли какая-то конкретная причина, по которой вам это не нравится? – AakashM

+0

нет причин не любить :). Мне просто интересно, есть ли еще пути. – mshsayem

ответ

2

Я не думаю, LINQ to Entities имеет приятный запрос для этой ситуации.
Другим решением является использование использованием Entity SQL (ESQL)

var fromDate = new DateTime(2011, 02, 01); 
var toDate = new DateTime(2012, 02, 01); 
var esql = @"select 
      sum(it.TransactionCount) as SumOfTransactionCount, 
      sum(it.RejectCount) as SumOfRejectCount 
       from ActivityCaches as it 
       where it.Date > @fromDate and it.Date <= @toDate"; 
var query = CreateQuery<DbDataRecord>(esql, 
     new ObjectParameter("fromDate", fromDate) , 
     new ObjectParameter("toDate", toDate)); 
+2

Я не люблю запросы в строке. Но, кажется, вы правы, говоря: «Я не думаю, что LINQ to Entities имеет хороший запрос для этой ситуации». Я буду придерживаться '.GroupBy (g => 1)' – mshsayem

1

Другого путь:

  1. Использование Entity SQL
  2. Применить 3 отдельных SUM s
+0

Можете ли вы показать несколько примеров/ссылок? – mshsayem

+1

@mshsayem, http://msdn.microsoft.com/en-us/library/bb387145.aspx –

0

В Linq Aggregate() метод позволяет суммирования без группировки, как показано ниже. Я боюсь, что я не настроил его на БД, поэтому я не буду гарантировать, что ошибка Linq to Sql не будет всплывать. Если это произойдет, вы можете попробовать Explout ToList() в ActivityCaches(), прежде чем делать Aggregate(), но после where().

Update

Я обновил код, чтобы работать и модель EF. Создал небольшую EF-модель для замены SomeEntry и обновил данные, чтобы убедиться, что я читал из БД.

EF Model for ActivityLog

private static ActivityLog Aggregate(ActivityLog agg, ActivityLog entry) { 
    agg.TranCount += entry.TranCount; 
    agg.ReqCount += entry.ReqCount; 
    return agg; 
} 

[TestMethod] 
public void AggregateFirstThree() { 

    var context = new TestDBEntities(); 

    var startDate = new DateTime(2012, 1, 1); 
    var endDate = new DateTime(2012, 1, 3); 

    var aggregate = new ActivityLog(); 

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate); 

    Assert.AreEqual(66, aggregate.TranCount); 
    Assert.AreEqual(36, aggregate.ReqCount); 

} 

[TestMethod] 
public void AggregateLastThree() { 

    var context = new TestDBEntities(); 

    var startDate = new DateTime(2012, 1, 4); 
    var endDate = new DateTime(2012, 1, 6); 

    var aggregate = new ActivityLog(); 

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate); 

    Assert.AreEqual(75, aggregate.TranCount); 
    Assert.AreEqual(45, aggregate.ReqCount); 

} 

НТН,
Алан.

+0

Это не работает с EF –

+0

@Adrian Iftode Просто попробовал, и EF-модель работала нормально. Не нужно было добавлять ToList(). Будет обновлен код для отражения изменений. – AlanT

+0

милый, я был так уверен: P –

0

Неясно из вашего вопроса, где вы хотите сохранить результат. Если вы планируете хранить его в двух переменных, вы можете получить данные, использовать метод расширения .Where() для фильтрации по диапазону дат, а затем использовать метод расширения .Sum() для вычисления значения суммы. Что-то вдоль этих линий:

var result = your_query.Where(m => m.Date >= startingDate && m.Date <= endingDate); 
var totalTxCount = result.Sum(m => m.TransactionCount); 
var totalRejectCount = result.Sum(m => m.RejectCount); 
+0

Да, но в этом случае будет более одного запроса ... – mshsayem