views:

74

answers:

1

I have an audit table which stores audit rows for a long running process at an individual task level in SQL Server.

  • auditId int,
  • TaskName nvarchar(255),
  • StartTime datetime,
  • EndTime (datetime, null),
  • Status (nvarchar(255), null)

The process contains parent and child steps and each step is logged to the audit table. A task may or may not have a parent.

e.g.

auditId, TaskName, StartTime, EndTime, Status

  1. Parent1, 09:30:00, 09:40:00, Valid
  2. Child1, 09:30:01, 09:35:00, Valid
  3. Child2, 09:35:01, 09:40:00, Valid
  4. Parent2, 09:40:01, null, null
  5. Child3, 09:40:02, null, null

Using C# 4.0 / LINQ to Entities / LINQ over an ObservableCollection I would like to get an Audit summary from this table for the past X days containing the total duration for each day by status. I can pivot the individual records to generate the summary if I can figure out how to get the summary audit records.

In the Audit summary there should:

  1. Not be any overlapping audit records otherwise will double count the duration.
  2. Need to handle the fact that there may be tasks which are still running for the current date and return a null
  3. Need to handle the lag between the end of the previous task and the start of the next task. Probably by getting the duration between the start of the current task and the start of the next task instead of the end of the current task.
  4. Handle the null for the final task of the day which won't have a following start time if I use the start time of the next record as described in point 3

So using the example above the summary records would be:

auditId, TaskName, StartTime, EndTime, Status

  1. Parent1, 09:30:00, 09:40:01, Valid
  2. Parent2, 09:40:01, null, null

Any ideas?

Thanks

A: 

Found quite a few "interesting" things about EF and dates while figuring out how to do this.

So in the end I:

  1. Extended the audit log table to add in a new nullable DateTime StartDateTimeOfNext and private _startDateTimeOfNext to cache the previous value. Once calculated I didn't want to have to calculate it again
  2. Added an Entity Context to the same partial class
  3. Extended the Audit table class to add the code below.
  4. I used DateTime.Today for the DefaultIfEmpty as SQL Server 2005 doesn't support the C# DateTime.MinValue and DateTime.MaxValue
  5. Its not particularly beautiful but it works
  public DateTime? StartDateTimeOfNext
{  
    get  
    {  
        if (_startDateTimeOfNext == null)  
        {  
            DateTime windowMin = this.StartTime.Date;
            DateTime windowMax = this.StartTime.Date.AddDays(1).AddMinutes(-1);
            DateTime? query = (from nextAuditLog in AuditLog.AuditLogEntityContext.AuditLogs
            where nextAuditLog.auditId > this.auditId 
            && nextAuditLog.StartTime > this.StartTime 
            && nextAuditLog.StartTime <= windowMax 
            && nextAuditLog.StartTime >= windowMin
            orderby nextAuditLog.auditId ascending
            select nextAuditLog.StartTime
            ).DefaultIfEmpty(DateTime.Today).First();               
            if (query != DateTime.Today)
            {
                _startDateTimeOfNext = query;
                return query;
            }
            else
            {
                _startDateTimeOfNext = this.EndTime;
                return this.EndTime;
            }
        }
        else
        {
        return _startDateTimeOfNext;
        }
    }
}
Cynicszm