如何选择多列的聚合(没有分组)?

时间:2012-02-13 03:50:48

标签: c# .net linq entity-framework linq-to-entities

假设我有一个这样的汇总表:

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(在这种情况下不喜欢)。 任何更好的想法(没有分组)?

P.S:我无法更改数据库架构

4 个答案:

答案 0 :(得分: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));

答案 1 :(得分:1)

另一种方式:

  1. 使用实体SQL
  2. 应用3个单独的SUM s

答案 2 :(得分:0)

Linq Aggregate()方法允许在不进行分组的情况下进行求和,如下所示。我担心我没有对数据库进行设置,所以我不保证不会弹出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);

}

hth,
艾伦。

答案 3 :(得分: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);