2012-02-13 58 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:我不会成为能够改变DB模式

+1

那么,T-SQL是*隐含*做分组操作,它只是所有的记录都在同一组,这是一样的,你用你的'的GroupBy(做什么a => 1)'。你有什么特别的理由不喜欢这个吗? – AakashM 2012-02-13 09:23:17

+0

没有理由不喜欢:)。我只是想知道是否有更多的方法。 – mshsayem 2012-02-14 03:14:04

回答

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 2012-02-14 03:45:18

1

另一种方式:

  1. 使用实体SQL
  2. 应用3个独立的SUM小号
+0

你能展示一些例子/链接吗? – mshsayem 2012-02-13 04:37:08

+1

@mshsayem,http://msdn.microsoft.com/en-us/library/bb387145。aspx – 2012-02-13 09:25:52

0

LINQ的聚合(使用)方法允许在没有如下分组求和。恐怕我没有将它设置为对数据库,所以我不能保证Linq to Sql错误不会弹出。如果发生这种情况,可以在执行Aggregate()之前但在where()之后,在ActivityCaches()上尝试一个显式ToList()。

更新

我更新的代码和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 – 2012-02-13 12:21:41

+0

工作@Adrian Iftode刚刚试了一下,EF模型,工作得很好。甚至不需要添加ToList()。将更新代码以反映更改。 – AlanT 2012-02-13 13:45:39

+0

不错,我很确定:P – 2012-02-13 13:52:00

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 2012-02-14 03:10:48