/// <summary>
        /// Insert the specified data.
        /// </summary>
        /// <param name="data">Data.</param>
        public virtual TData Insert(TData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            DataPersistencePreEventArgs <TData> preArgs = new DataPersistencePreEventArgs <TData>(data);

            this.Inserting?.Invoke(this, preArgs);
            if (preArgs.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event handler indicates abort insert for {0}", data);
                return(data);
            }

#if PERFMON
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif

            // Persist object
            using (var context = this.CreateConnection())
                try
                {
                    using (context.LockConnection())
                    {
                        try
                        {
                            this.m_tracer.TraceVerbose("INSERT {0}", data);

                            context.Connection.BeginTransaction();
                            data = this.Insert(context, data);
                            context.Connection.Commit();
                            // Remove from the cache
                            foreach (var itm in context.CacheOnCommit.AsParallel())
                            {
                                ApplicationContext.Current.GetService <IDataCachingService>().Add(itm);
                            }
                        }
                        catch (Exception e)
                        {
                            this.m_tracer.TraceError("Error : {0}", e);
                            context.Connection.Rollback();
                            throw new LocalPersistenceException(DataOperationType.Insert, data, e);
                        }
                    }
                    this.Inserted?.Invoke(this, new DataPersistenceEventArgs <TData>(data));
                    return(data);
                }
                catch { throw; }

#if PERFMON
            finally
            {
                sw.Stop();
                ApplicationContext.Current.PerformanceLog(typeof(TData).Name, nameof(Insert), "Complete", sw.Elapsed);
            }
#endif
        }
        /// <summary>
        /// Obsolete the specified identified data
        /// </summary>
        /// <param name="data">Data.</param>
        public virtual TData Obsolete(TData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            else if (!data.Key.HasValue || data.Key == Guid.Empty)
            {
                throw new InvalidOperationException("Data missing key");
            }
#if PERFMON
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif
            DataPersistencePreEventArgs <TData> preArgs = new DataPersistencePreEventArgs <TData>(data);
            this.Obsoleting?.Invoke(this, preArgs);
            if (preArgs.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event handler indicates abort for {0}", data);
                return(data);
            }

            // Obsolete object
            using (var context = this.CreateConnection())
                try
                {
                    using (context.LockConnection())
                    {
                        try
                        {
                            this.m_tracer.TraceVerbose("OBSOLETE {0}", data);
                            context.Connection.BeginTransaction();

                            data = this.Obsolete(context, data);

                            context.Connection.Commit();

                            // Remove from the cache
                            foreach (var itm in context.CacheOnCommit.AsParallel())
                            {
                                ApplicationContext.Current.GetService <IDataCachingService>().Remove(itm.Key.Value);
                            }
                        }
                        catch (Exception e)
                        {
                            this.m_tracer.TraceError("Error : {0}", e);
                            context.Connection.Rollback();
                            throw new LocalPersistenceException(DataOperationType.Obsolete, data, e);
                        }
                    }
                    this.Obsoleted?.Invoke(this, new DataPersistenceEventArgs <TData>(data));

                    return(data);
                }
                catch { throw; }
#if PERFMON
            finally
            {
                sw.Stop();
                ApplicationContext.Current.PerformanceLog(typeof(TData).Name, nameof(Obsolete), "Complete", sw.Elapsed);
            }
#endif
        }
 /// <summary>
 /// Fire inserting event
 /// </summary>
 protected void FireInserting(DataPersistencePreEventArgs <TData> evt)
 {
     this.Inserting?.Invoke(this, evt);
 }