public void Save(Debug debugResult, bool async)
        {
            Action<Debug> action = (debug) => {
                using (var profilerDataContext = new ProfilerDbDataContext())
                {
                    var transactionId = Guid.Empty;
                    Guid.TryParse(debug.TransactionId, out transactionId);

                    profilerDataContext.InsertProfilerDebug(Guid.Parse(debug.Id), debug.Name, debug.Method,
                        debug.RequestUrl, debug.MachineName, debug.UserName, debug.StartedUtc,
                        transactionId, debug.Code, debug.Level);

                    if (debug.Head != null)
                    {
                        var timing = debug.Head;
                        InsertTimings(profilerDataContext, transactionId, timing);
                    }
                }
            };

            if (RequiredToSave() == true)
            {
                if (async)
                    action.BeginInvoke(debugResult, null, null);
                else
                    action.Invoke(debugResult);
            }
        }
        public List<SqlTiming> GetSqlTimings(string transactionId, string timingId)
        {
            List<SqlTiming> result = new List<SqlTiming>();
            var profilerDataContext = new ProfilerDbDataContext();

            var sqlResults = profilerDataContext.GetSqlTimings(Guid.Parse(timingId), Guid.Parse(transactionId));
            foreach (var sqlResult in sqlResults)
            {
                var preservedSqlResult = result.Find(x => x.Id == sqlResult.SqlTimingId.ToString());
                if ((preservedSqlResult == null) == true)
                {
                    preservedSqlResult = new SqlTiming();
                    preservedSqlResult.CommandString = sqlResult.CommandString ??  UNKNOWN;
                    preservedSqlResult.DurationMilliseconds = sqlResult.DurationMilliseconds.GetValueOrDefault();
                    preservedSqlResult.ExecuteType = sqlResult.ExecuteType ?? UNKNOWN;
                    preservedSqlResult.FirstFetchDurationMilliseconds = sqlResult.FirstFetchDurationMilliseconds.GetValueOrDefault();
                    preservedSqlResult.Id = sqlResult.SqlTimingId.ToString();
                    preservedSqlResult.Order = sqlResult.ProfiledOrder.GetValueOrDefault();
                    preservedSqlResult.StartMilliseconds = sqlResult.StartMilliseconds.GetValueOrDefault();
                    preservedSqlResult.TimingId = sqlResult.TimingId.ToString();
                    result.Add(preservedSqlResult);
                }
                BuildSqlParameter(sqlResult, preservedSqlResult);
            }
            return result;
        }
        public Debug GetTimings(string transactionId)
        {
            var transactionIdGuid = Guid.Parse(transactionId);
            var profilerDataContext = new ProfilerDbDataContext();
            var traces = profilerDataContext.GetTraceAndTimings(transactionIdGuid);

            Debug result = new Debug();

            List<Timing> allTimings = new List<Timing>();
            foreach (var trace in traces)
            {
                if (trace.IsRoot.GetValueOrDefault() == true) {
                    BuildDebugAndRoot(trace, result);
                }
                else{
                    var timing = new Timing();
                    BuildTiming(trace, timing);
                    BuildSqlTimingCount(trace, timing);
                    allTimings.Add(timing);
                }
            }

            if(allTimings.Count > 0)
                MapChildren(result.Head, allTimings);
            return result;
        }
        private static void InsertTimings(ProfilerDbDataContext profilerDataContext, Guid transactionId, Timing timing)
        {
            var timingId = Guid.Empty;
            Guid.TryParse(timing.Id, out timingId);
            profilerDataContext.InsertProfilerTiming(timingId, transactionId, timing.IsRoot, timing.Name, timing.KeyValues,
                    timing.Duration, timing.DurationWithOutChildren, timing.Start, Guid.Parse(timing.ParentId), timing.Order,
                    timing.SqlTimingDuration, timing.ExecutedScalers, timing.ExecutedNonQueries, timing.ExecutedReaders, timing.ManagedThreadId);

            foreach (var sqlTiming in timing.SqlTimings)
            {
                var sqlTimingId = Guid.Empty;
                Guid.TryParse(sqlTiming.Id, out sqlTimingId);
                profilerDataContext.InsertProfilerSqlTiming(sqlTiming.ExecuteType, sqlTiming.CommandString, sqlTiming.StartMilliseconds,
                    sqlTiming.DurationMilliseconds, sqlTiming.FirstFetchDurationMilliseconds, timingId, transactionId, sqlTiming.Order, sqlTimingId);
                foreach (var sqlParameter in sqlTiming.Parameters)
                {
                    profilerDataContext.InsertProfilerSqlParameter(sqlTimingId, sqlParameter.Name, sqlParameter.Value,
                        sqlParameter.DbType, sqlParameter.Size);
                }
            }

            if (timing.Children.Count > 0)
            {
                foreach (var childTiming in timing.Children)
                {
                    InsertTimings(profilerDataContext, transactionId, childTiming);
                }
            }
        }