public List<LimitStatsByDay> GetLimitStatsByDay(IOWLimit limit, DateTime? startTimestamp, DateTime? endTimestamp) { List<LimitStatsByDay> stats = new List<LimitStatsByDay>(); DateTime startDay = NormalizeStartDay(startTimestamp); DateTime endDay = NormalizeEndDay(startDay, endTimestamp); if (limit != null) stats = GetLimitStatsOneLimit(limit, startDay, endDay); return stats; }
private List<LimitStatsByDay> GetLimitStatsOneLimit(IOWLimit limit, DateTime startDay, DateTime endDay) { List<LimitStatsByDay> stats = new List<LimitStatsByDay>(); // Build a date array for what SHOULD be in the statistics table for each variable List<DateTime> datetimes = new List<DateTime>(); for (DateTime dt = startDay; dt < endDay; dt = dt.AddDays(1)) datetimes.Add(dt); // This query returns the Cartesian product of all limits and dates var query1 = from lim in _iowLimitRespository.GetAllList(p => p.Id == limit.Id) from dt in datetimes orderby lim.Id, dt select new { LimitId = lim.Id, LevelName = lim.Level.Name, Criticality = lim.Level.Criticality, Direction = lim.Direction, Day = dt }; var allLimitsAndDates = query1.ToList(); // This query joins the Cartesian product to the stats table, and fills in zeros whenever the stats table lacks a record var query2 = from a in allLimitsAndDates join s in _iowStatsByDayRepository.GetAllList(p => p.Day >= startDay && p.Day <= endDay) on new { LimitId = a.LimitId, Day = a.Day } equals new { LimitId = s.IOWLimitId, Day = s.Day } into joinedStats from t in joinedStats.DefaultIfEmpty( new IOWStatsByDay { NumberDeviations=0, DurationHours=0 }) orderby a.LimitId, a.Day select new { LimitId=a.LimitId, LevelName=a.LevelName, Criticality=a.Criticality, Direction=a.Direction, Day=a.Day, NumberDeviations=t.NumberDeviations, DurationHours=t.DurationHours}; var results = query2.ToList(); if( results != null ) { LimitStatsByDay stat = null; LimitStatsByDay lastStat = null; foreach(var d in results) { if( lastStat == null || lastStat.LimitId != d.LimitId ) { if (lastStat != null) stats.Add(stat); stat = new LimitStatsByDay { LimitId = d.LimitId, LevelName = d.LevelName, Criticality = d.Criticality, Direction = d.Direction, Days = new List<LimitStatDays>() }; } stat.Days.Add(new LimitStatDays { Day = d.Day, NumberDeviations = d.NumberDeviations, DurationHours = d.DurationHours }); lastStat = stat; } stats.Add(stat); } return stats; }
/* * CalculateStatisticsForOneLimit() * * Handles a single limit for a specified time period. It reads the deviation table (IOWDeviation), * chunks up deviations by day, and stores the results in the stats table (IOWStatsByDay). * * Since deviations can change as new tag data are received, the statistics table (which is derived from the deviations * table) can also change. As changes are hard to figure out, this routine simply zeros out the stats table for the limit * and time period in question, and recalculates the statistics for each day of interest. * * May be called by UpdateStatistics(), which loops through all limits. Can also be triggered when deviations are updated. */ public int CalculateStatisticsForOneLimit(IOWLimit limit, DateTime? startTimestamp, DateTime? endTimestamp) { int numberRecordsUpdated = 0; // This routine calculates IOW deviation statistics for one limit for a specified time range. // The start and end time must be at midnight, to match the records expected in IOWStatsByDay. // Validation must be done by the caller. // The start and end times must be at midnight. Limit the time period to the last 60 days. // Default calculations to today. DateTime startDay = NormalizeStartDay(startTimestamp); DateTime endDay = NormalizeEndDay(startDay, endTimestamp); // Get any stats that already exist for the time period of interest, and zero out the data. // Do this before getting the deviations because it is possible that there are not any deviations, in which case // the stats should be zeroed. List<IOWStatsByDay> allStats = _iowStatsByDayRepository.GetAllList(p => p.IOWLimitId == limit.Id && p.Day >= startDay && p.Day <= endDay).ToList(); if( allStats != null && allStats.Count > 0 ) { allStats.Select(p => { p.NumberDeviations = 0; p.DurationHours = 0; return p; }).ToList(); /*foreach(IOWStatsByDay stat in allStats) { stat.NumberDeviations = 0; stat.DurationHours = 0; }*/ } List<IOWDeviation> deviations = GetDeviations(limit.Id, startDay); if( deviations != null && deviations.Count > 0 ) { IOWStatsByDay stat = null; // Set the last end day to before the start of the processing period DateTime startDeviation, endDeviation; foreach(IOWDeviation dev in deviations) { // startDay = midnight on the day when the deviation starts; clamped to be no earlier than startTimestamp in the arguments // endDay = midnight on the day after startDay // startDeviation = start of the deviation for this day's statistics; clamped to be no earlier than startDay // endDeviation = end of the deviation for this day's statistics; allowed to be beyond the end of this day; defaults to now if (dev.StartTimestamp < startDay) { startDeviation = startDay; } else { startDay = dev.StartTimestamp.Date; startDeviation = dev.StartTimestamp; } if (dev.EndTimestamp.HasValue) endDeviation = dev.EndTimestamp.Value; else endDeviation = DateTime.Now; // Process this deviation until we run out of days. bool insertNewRecord = false; while ( startDeviation < endDeviation ) { endDay = startDay.AddDays(1); double durationHours = ((endDeviation <= endDay ? endDeviation : endDay) - startDeviation).TotalHours; // If we already have a stat record (from earlier in the loop) and it was for a different time period and it was created here, // then insert it and start over. Otherwise, keep the last stat record as we might want to reuse it. if (stat != null && stat.Day != startDay && insertNewRecord) { _iowStatsByDayRepository.Insert(stat); allStats.Add(stat); stat = null; insertNewRecord = false; } // Look for an already existing stat record to update. // If we do not already have a stat record OR the dates don't match, look for an existing one in the database // If we can't find a stat record in the database, then create a new record. We'll insert it later. if (stat == null || stat.Day != startDay) { stat = allStats.FirstOrDefault(p => p.Day == startDay); if (stat == null) { stat = new IOWStatsByDay { IOWLimitId = limit.Id, Day = startDay, NumberDeviations = 0, DurationHours = 0, TenantId = limit.TenantId }; insertNewRecord = true; } else insertNewRecord = false; } else insertNewRecord = false; // Update the stat record with new information stat.NumberDeviations++; stat.DurationHours += durationHours; numberRecordsUpdated++; // Move to the next day. Look to see if this deviation slides into the following day startDay = startDay.AddDays(1); endDay = startDay.AddDays(1); startDeviation = startDay; } // Handle the last record, if any if (insertNewRecord) { _iowStatsByDayRepository.Insert(stat); allStats.Add(stat); } // ABP will automatically update open records, so no need to call the Update() method on IOWStatByDay. } // foreach(IOWDeviation dev in deviations) } // if( deviations != null && deviations.Count > 0 ) return numberRecordsUpdated; }
public long InsertOrUpdateLimitAndGetId(IOWLimit input) { IOWLimit limit = null; // If the limit id is present, assume the limit exists. // Otherwise check to see if this limit exists. if (input.Id > 0) limit = FirstOrDefaultLimit(input.Id); else limit = FirstOrDefaultLimit(input.IOWVariableId, input.IOWLevelId); if (limit == null) limit = new IOWLimit { TenantId = input.TenantId, IOWVariableId = input.IOWVariableId, IOWLevelId = input.IOWLevelId }; limit.StartDate = input.StartDate; limit.EndDate = input.EndDate; limit.Direction = input.Direction; limit.Value = input.Value; limit.Cause = input.Cause; limit.Consequences = input.Consequences; limit.Action = input.Action; limit.LastCheckDate = input.LastCheckDate; limit.LastStatus = input.LastStatus; limit.LastDeviationStartTimestamp = input.LastDeviationStartTimestamp; limit.LastDeviationEndTimestamp = input.LastDeviationEndTimestamp; return _iowLimitRespository.InsertOrUpdateAndGetId(limit); }
public LimitDto UpdateLimit(UpdateLimitInput input) { DateTime oldestDate = new DateTime(2014, 1, 1); // This method accepts one limit for one variable. // If the limit does not exist, it is added. // If the limit exists, it is changed or deleted. LimitDto output = null; bool inputIsValid = false; bool isActive = input.IsActive.HasValue ? input.IsActive.Value : true; // Look for the variable. IOWVariable variable = _iowManager.FirstOrDefaultVariable(input.IOWVariableId, input.VariableName); if( variable != null ) { // Does the specified limit exist? If so, get it. This will return null if nothing is found. IOWLimit limit = _iowManager.FirstOrDefaultLimit(variable.Id, input.Id, input.LevelName); // Does the specified level exist? It should. IOWLevel level = _iowManager.FirstOrDefaultLevel(input.IOWLevelId, input.LevelName); // There are five possibilities at this point: // 1) We did not find a level ==> bad input, do nothing // 2) We found a level, found a limit, isActive flag is true ==> update an existing limit // 3) We found a level, found a limit, IsActive flag is false ==> delete an existing limit // 4) We found a level, did not find a limit, IsActive flag is true ==> insert a new limit // 5) We found a level, did not find a limit, IsActive flag is false ==> do nothing if ( level == null ) { // Case 1: Bad input } else if ( isActive ) { // Case 2: IsActive is true AND limit exists ==> update an existing limit // Case 4: IsActive is true AND limit does not exist ==> insert a new limit // For case 4 (limit does not exist), need to create a limit record to continue if ( limit == null ) limit = new IOWLimit { IOWVariableId = variable.Id, IOWLevelId = level.Id, LastCheckDate = null, LastStatus = IOWStatus.Normal, LastDeviationStartTimestamp = null, LastDeviationEndTimestamp = null, TenantId = variable.TenantId }; limit.StartDate = new DateTime(Math.Max(input.StartDate.Ticks, oldestDate.Ticks)); limit.EndDate = input.EndDate; limit.Direction = input.Direction; limit.Value = input.Value; limit.Cause = input.Cause; limit.Consequences = input.Consequences; limit.Action = input.Action; limit.Id = _iowManager.InsertOrUpdateLimitAndGetId(limit); inputIsValid = true; } else if ( limit != null && !isActive ) { // Case 3: Limit exists and should be deleted _iowManager.DeleteLimit(limit.Id); inputIsValid = true; } if( inputIsValid ) output = new LimitDto { Id = limit.Id, IOWVariableId = variable.Id, IsActive = (limit != null && isActive ) ? true : false, IOWLevelId = limit.IOWLevelId, Name = level.Name, Criticality = level.Criticality, StartDate = limit.StartDate, EndDate = limit.EndDate, Direction = limit.Direction, Value = limit.Value, Cause = limit.Cause, Consequences = limit.Consequences, Action = limit.Action }; } return output; }