/// <summary>
        /// Fids the specified audit in the local repository
        /// </summary>
        public IEnumerable <AuditData> Find(Expression <Func <AuditData, bool> > query, int offset, int?count, out int totalResults)
        {
            try
            {
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var builder = new QueryBuilder(this.m_mapper);
                    var sql     = builder.CreateQuery(query).Build();
                    sql = sql.OrderBy <DbAuditData>(o => o.Timestamp, SortOrderType.OrderByDescending);

                    // Total results
                    totalResults = conn.ExecuteScalar <Int32>($"SELECT COUNT(*) FROM ({sql.SQL})", sql.Arguments.ToArray());

                    // Query control
                    if (count.HasValue)
                    {
                        sql.Limit(count.Value);
                    }
                    if (offset > 0)
                    {
                        if (count == 0)
                        {
                            sql.Limit(100).Offset(offset);
                        }
                        else
                        {
                            sql.Offset(offset);
                        }
                    }
                    sql = sql.Build();
                    var itm = conn.Query <DbAuditData.QueryResult>(sql.SQL, sql.Arguments.ToArray());
                    AuditUtil.AuditAuditLogUsed(ActionType.Read, OutcomeIndicator.Success, sql.ToString(), itm.Select(o => new Guid(o.Id)).ToArray());
                    return(itm.Select(o => this.ToModelInstance(conn, o)).ToList());
                }
            }
            catch (Exception e)
            {
                AuditUtil.AuditAuditLogUsed(ActionType.Read, OutcomeIndicator.EpicFail, query.ToString());
                this.m_tracer.TraceError("Could not query audit {0}: {1}", query, e);
                throw;
            }
        }
        /// <summary>
        /// Prune the audit database
        /// </summary>
        public void Prune()
        {
            var config = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            try
            {
                this.m_tracer.TraceInfo("Prune audits older than {0}", config?.AuditRetention);
                if (config?.AuditRetention == null)
                {
                    return;                                 // keep audits forever
                }
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    try
                    {
                        conn.BeginTransaction();
                        DateTime cutoff = DateTime.Now.Subtract(config.AuditRetention);
                        Expression <Func <DbAuditData, bool> > epred = o => o.CreationTime < cutoff;
                        conn.Table <DbAuditData>().Delete(epred);

                        // Delete objects
                        conn.Execute($"DELETE FROM {conn.GetMapping<DbAuditObject>().TableName} WHERE NOT({conn.GetMapping<DbAuditObject>().FindColumnWithPropertyName(nameof(DbAuditObject.AuditId)).Name} IN " +
                                     $"(SELECT {conn.GetMapping<DbAuditData>().FindColumnWithPropertyName(nameof(DbAuditData.Id)).Name} FROM {conn.GetMapping<DbAuditData>().TableName})" +
                                     ")");

                        AuditUtil.AuditAuditLogUsed(ActionType.Delete, OutcomeIndicator.Success, epred.ToString());
                        conn.Commit();
                    }
                    catch
                    {
                        conn.Rollback();
                    }
                }
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error pruning audit database: {0}", e);
                throw;
            }
        }
        /// <summary>
        /// Get the specified audit data from the database
        /// </summary>
        public AuditData Get(object id)
        {
            try
            {
                Guid pk = Guid.Empty;
                if (id is Guid)
                {
                    pk = (Guid)id;
                }
                else if (id is String)
                {
                    pk = Guid.Parse(id.ToString());
                }
                else
                {
                    throw new ArgumentException("Parameter must be GUID or parsable as GUID", nameof(id));
                }

                // Fetch
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var builder = new QueryBuilder(this.m_mapper);
                    var sql     = builder.CreateQuery <AuditData>(o => o.CorrelationToken == pk).Limit(1).Build();

                    var res = conn.Query <DbAuditData.QueryResult>(sql.SQL, sql.Arguments.ToArray()).FirstOrDefault();
                    AuditUtil.AuditAuditLogUsed(ActionType.Read, OutcomeIndicator.Success, sql.ToString(), pk);

                    return(this.ToModelInstance(conn, res, false));
                }
            }
            catch (Exception e)
            {
                AuditUtil.AuditAuditLogUsed(ActionType.Read, OutcomeIndicator.EpicFail, id.ToString());
                this.m_tracer.TraceError("Error retrieving audit {0} : {1}", id, e);
                throw;
            }
        }