简体   繁体   English

有没有更优雅的解决方案来计算在Entity Framework中正在发生某个值的Timespan?

[英]Is there a more elegant solution to calculating the Timespan that a certain value is occurring in Entity Framework?

My problem: I have a table in our database that is called DevicePropertyUpdates. 我的问题:我的数据库中有一个名为DevicePropertyUpdates的表。 We use this table to record a state change in a device. 我们使用此表记录设备中的状态更改。 I need to know the total amount of time that a certain mode is active during a specified time range. 我需要知道特定模式在指定时间范围内处于活动状态的总时间。

For example, if it is mode A from 00:00 to 4:00, mode B from 4:00 to 10:00, mode A from 10:00 to 16:00, and Mode C from 16:00 to 24:00. 例如,如果模式A从00:00到4:00,模式B从4:00到10:00,模式A从10:00到16:00,模式C从16:00到24:00 。 If I want to know how long mode A was active for the day, I add up 00:00 to 4:00 and 10:00 to 16:00 and get 10 total hours. 如果我想知道模式A在一天中处于激活状态的时间,我将00:00到4:00和10:00到16:00加起来,总共得到10个小时。

My current code is below. 我当前的代码如下。 Very iterative and I believe will force entity framework to materialize all these modes for the entire date range. 非常迭代,我相信它将迫使实体框架在整个日期范围内实现所有这些模式。 I'm looking for a more elegant solution just to further my problem solving ability and to write cleaner code. 我正在寻找一种更优雅的解决方案,以提高我的问题解决能力并编写更简洁的代码。 I'm hoping I just missed something obvious that I can learn from. 我希望我只是想念一些可以学到的东西。 The kind of ideas I was consisering was .Zip, .GroupBy, or some kind of join to find the differences but I couldn't think of anything useful. 我考虑的想法是.Zip,.GroupBy或某种联接来发现差异,但是我想不出任何有用的方法。

The architect prefers an entity framework approach to this. 架构师更喜欢使用实体框架方法。 The DevicePropertyUpdates table has the following structure. DevicePropertyUpdates表具有以下结构。

Timestamp - datetime 时间戳记-日期时间

StringValue - varchar(max) StringValue-varchar(最大值)

Name - varchar(100) 名称-varchar(100)

Sample SQL 示例SQL

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

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

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

Row 4: "OperatingMode", "A", "7/1/2014 3:33:00" 第4行:“ OperatingMode”,“ 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;
}

You could sum up all the ON Times from Timestamp till endtime. 您可以总结从时间戳到结束时间的所有“打开时间”。 Then sum all the IDLE time and sumstract the result. 然后将所有空闲时间相加并求和。 This would require two SQL Statements and a resultset that follows a few rules. 这将需要两个SQL语句和一个遵循一些规则的结果集。 It has to start with an ON an end with an IDLE an every ON must have a corresponding IDLE. 它必须以ON开头,以IDLE结尾,每个ON必须有一个对应的IDLE。

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


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

Your Linq would look like this. 您的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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM