My problem: I have a table in our database that is called 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. 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.
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.
The architect prefers an entity framework approach to this. The DevicePropertyUpdates table has the following structure.
Timestamp - datetime
StringValue - varchar(max)
Name - varchar(100)
Sample SQL
Row 1: "OperatingMode", "A", "7/1/2014 1:00:00"
Row 2: "OperatingMode", "A", "7/1/2014 2:00:00"
Row 3: "OperatingMode", "B", "7/1/2014 2:15:00"
Row 4: "OperatingMode", "A", "7/1/2014 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. 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 |
------------------------------------------------------------------
-------------------------------------------------
-------------------------
----------------------------------------------------------
------------------------------------------
----------------
Your Linq would look like this.
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);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.