是否有一个更优雅的解决方案来计算Timespan,在实体框架中发生了某个值?

时间:2014-07-11 15:49:17

标签: c# .net linq entity-framework entity-framework-4

我的问题:我的数据库中有一个名为DevicePropertyUpdates的表。我们使用此表记录设备中的状态更改。我需要知道某个模式在指定时间范围内处于活动状态的总时间。

例如,如果是00:00到4:00的模式A,模式B从4:00到10:00,模式A从10:00到16:00,模式C从16:00到24:00。如果我想知道当天模式A有多长时间,我将00:00加到4:00和10:00到16:00加起来,总共得到10个小时。

我目前的代码如下。非常迭代,我相信将迫使实体框架在整个日期范围内实现所有这些模式。我正在寻找一个更优雅的解决方案,以提高我的解决问题的能力,并编写更清晰的代码。我希望我只是错过了一些我能学到的东西。我所设想的那种想法是.Zip,.GroupBy,或某种联系来找到差异,但我想不出任何有用的东西。

架构师更喜欢实体框架方法。 DevicePropertyUpdates表具有以下结构。

时间戳 - 日期时间

StringValue - varchar(max)

名称 - varchar(100)

示例SQL

第1行:“OperatingMode”,“A”,“7/1/2014 1:00:00”

第2行:“OperatingMode”,“A”,“7/1/2014 2:00:00”

第3行:“OperatingMode”,“B”,“2014年7月1日2:15:00”

第4行:“操作模式”,“A”,“2014年7月1日3:33:00”

using (Container container = ContextFactory.CreateInstance())
{
    IEnumerable<Model.DevicePropertyUpdate> updates =
        container.DevicePropertyUpdates.Where(
            dpu => dpu.Name == "OperatingMode" && dpu.Timestamp <= endTime && dpu.Timestamp >= startTime);

    TimeSpan totalTime = TimeSpan.Zero;
    DateTime? start = null;

    foreach (var update in updates)
    {
        if (update.StringValue == operatingMode)
        {
            if (!start.HasValue)
            {
                start = update.Timestamp;
            }
        }
        else
        {
            if (start.HasValue)
            {
                totalTime += update.Timestamp - startTime;
                start = null;
            }
        }
    }
    //Include edge case if matching operating mode was the last to occur in the time range.
    if (start.HasValue)
    {
        totalTime += endTime - startTime;
    }

    return totalTime;
}

1 个答案:

答案 0 :(得分:1)

你可以总结从时间戳到结束时间的所有ON时间。然后将所有IDLE时间相加并对结果进行求和。这将需要两个SQL语句和一个遵循一些规则的结果集。它必须以一个带有IDLE的ON结束开始,每个ON必须具有相应的IDLE。

|    ON     IDLE      ON     IDLE             ON       IDLE            |
     ------------------------------------------------------------------
                      -------------------------------------------------
                                              -------------------------


             ----------------------------------------------------------
                             ------------------------------------------
                                                       ---------------- 

你的Linq会是这样的。

using (var db = new TestContext()) {
    DateTime startDate = new DateTime(2014,05,01), endDate = new DateTime(2014,06,1);

    var baseQuery = db.DevicePropertyUpdates
                        .Where(p => p.TimeStamp >= startDate && p.TimeStamp < endDate)
                        .Where(p => p.Name == "OperatingMode");

    var OnSum = baseQuery.Where(p => p.StringValue == "ON")
                       .Sum(p => SqlFunctions.DateDiff("ss",p.TimeStamp, endDate));
    var IdleSum = baseQuery.Where(p => p.StringValue == "IDLE")
                       .Sum(p => SqlFunctions.DateDiff("ss", p.TimeStamp,endDate));

    var duration = TimeSpan.FromSeconds(OnSum.Value - IdleSum.Value);
}