/// <summary>
        /// Load all data in once for one customer ...
        /// </summary>
        /// <param name="database"></param>
        /// <param name="customerId"></param>
        /// <param name="getDatabase"></param>
        public void Initialize(DatabaseContext database, int customerId, FunctionGetDatabase getDatabase)
        {
            if (!_enable)
            {
                Info($"[{customerId}] No cache enabled ...");
                return;
            }

            _mutex.Wait(); // lock critical section

            if (_tick.ContainsKey(customerId))
            {
                _mutex.Release(); // unlock critical section
                Warn($"[{customerId}] Data are still loaded!");
                return;
            }

            if (_tables.Count == 0)
            {
                Debug("Initializing tables into the cache ...");

                foreach (KeyValuePair <string, DSDatabase> schema in ConfigurationManager.Schemas)
                {
                    foreach (KeyValuePair <string, DSTable> table in schema.Value.Tables)
                    {
                        if (_tables.ContainsKey(table.Key))
                        {
                            continue;
                        }

                        Verbose($"Initializing the table '{table.Key}' ({table.Value.Area}) ...");
                        _tables[table.Key] = table.Value;
                    }
                }

                Info($"{_tables.Count} tables initialized");
            }

            Info($"[{customerId}] Loading data ...");

            // Build the cache for the customer

            Dictionary <string, Dictionary <int, Tuple <DSRecord, InformationRecord> > > currentCache = null;

            if (!_records.ContainsKey(customerId))
            {
                Debug($"[{customerId}] Initializing tables ...");

                currentCache         = new Dictionary <string, Dictionary <int, Tuple <DSRecord, InformationRecord> > >(_tables.Count);
                _records[customerId] = currentCache;

                foreach (KeyValuePair <string, DSTable> table in _tables)
                {
                    currentCache[table.Key] = new Dictionary <int, Tuple <DSRecord, InformationRecord> >(table.Value.Capacity);
                }
            }
            else
            {
                currentCache = _records[customerId];
            }

            Lock(customerId, false);
            _mutex.Release(); // unlock critical section

            // sort all tables by area ...

            foreach (string area in _tables.Select(t => t.Value.Area).Distinct())
            {
                if (area == null)
                {
                    continue;
                }

                Debug($"Loading tables from the area '{area}' ...");

                try
                {
                    using (DatabaseContext currentContext = getDatabase(area))
                    {
                        // Load data into the current cache

                        foreach (KeyValuePair <string, DSTable> table in _tables.Where(t => t.Value.Area.Equals(area)))
                        {
                            try
                            {
                                Debug($"[{customerId}] Loading table '{table.Key}' ...");

                                // Load all records between the last tick and the new one (only for request successfully executed)

                                Dictionary <int, Tuple <DSRecord, InformationRecord> > currentTable = currentCache[table.Key];

                                foreach (Tuple <DSRecord, InformationRecord> record in table.Value.ReadRecords(currentContext, customerId))
                                {
                                    currentTable[record.Item1.Id] = record;
                                }

                                Info($"[{customerId}] {currentTable.Count} records read into the table '{table.Key}'");

                                GC.Collect();
                            }
                            catch (System.Exception ex)
                            {
                                Exception($"[{customerId}] Unable to initialize the cache", ex);
                            }
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    Exception($"[{customerId}] Unable to load the area {area}", ex);
                }
            }

            // Finalize the initialization of the cache for this customer

            _tick[customerId] = GetTick(database, customerId);
            Info($"[{customerId}] Cache initialized in tick {_tick[customerId]}");

            Unlock(customerId);
        }
        /// <summary>
        /// Check if the last tick loaded is different, and only load differences ...
        /// </summary>
        /// <param name="database"></param>
        /// <param name="customerId"></param>
        /// <param name="getDatabase"></param>
        public void UpdateCache(DatabaseContext database, int customerId, FunctionGetDatabase getDatabase)
        {
            if (!_enable)
            {
                return;
            }

            // Check if the customer is currently loaded

            if (!_tick.ContainsKey(customerId))
            {
                Initialize(database, customerId, getDatabase);
            }

            // the current customer is available

            Lock(customerId); // lock critical section

            // If the tick into the cache is not the same as the current one ... update the cache manager

            int currentTick  = GetTick(database, customerId);
            int previousTick = _tick[customerId];

            if (currentTick <= previousTick)
            {
                Unlock(customerId); // unlock critical section
                return;
            }

            Debug($"[{customerId}] Updating cache between {previousTick} and {currentTick} ...");
            int nbUpdates = 0;

            try
            {
                // Load all records between the last tick and the new one (only for request successfully executed)

                DSTable currentTable = null;
                Dictionary <int, Tuple <DSRecord, InformationRecord> > currentContent = null;
                foreach (RequestTableRecord request in database._RequestTable.Where(r => r.CustomerId == customerId &&
                                                                                    r.Id != null &&
                                                                                    previousTick < r.Tick && r.Tick <= currentTick).ToList().OrderBy(r => r.Table).ThenBy(r => r.Id))
                {
                    // new table ?

                    if (currentTable == null || !currentTable.Name.Equals(request.Table))
                    {
                        currentTable   = null;
                        currentContent = null;
                        if (!_tables.ContainsKey(request.Table))
                        {
                            if (IsVerbose())
                            {
                                Verbose($"[{customerId}] The table '{request.Table}' doesn't exist into the cache. May be, the table doesn't exist into the schemas");
                            }
                            continue;
                        }
                        currentTable   = _tables[request.Table];
                        currentContent = _records[customerId][request.Table];
                    }

                    // read the current record

                    Tuple <DSRecord, InformationRecord> currentRecord = currentTable.GetRecord(database, request.Id.Value, customerId);
                    if (currentRecord == null)
                    {
                        continue;
                    }

                    // Update the cache

                    currentContent[request.Id.Value] = currentRecord;
                    nbUpdates++;
                }

                _tick[customerId] = currentTick;
            }
            catch (System.Exception ex)
            {
                Exception($"[{customerId}] Unable to update the cache", ex);
            }

            Info($"[{customerId}] {nbUpdates} records loaded between {previousTick} and {currentTick}");

            Unlock(customerId); // Unlock the critical section
        }
        /// <summary>
        /// Load all data in once ...
        /// </summary>
        /// <param name="database"></param>
        /// <param name="customerIds">All customers Id to load</param>
        /// <param name="getDatabase"></param>
        public void Initialize(DatabaseContext database, List <int> customerIds, FunctionGetDatabase getDatabase)
        {
            if (!_enable)
            {
                Info($"No cache enabled ...");
                return;
            }

            if (_tables.Count == 0)
            {
                Debug("Initializing tables into the cache ...");

                foreach (KeyValuePair <string, DSDatabase> schema in ConfigurationManager.Schemas)
                {
                    foreach (KeyValuePair <string, DSTable> table in schema.Value.Tables)
                    {
                        if (_tables.ContainsKey(table.Key))
                        {
                            continue;
                        }

                        Verbose($"Initializing the table '{table.Key}' ({table.Value.Area}) ...");
                        _tables[table.Key] = table.Value;
                    }
                }

                Info($"{_tables.Count} tables initialized");
            }

            // Building the cache for all customers

            _mutex.Wait(); // lock critical section

            foreach (int customerId in customerIds)
            {
                Lock(customerId, false);

                // Build and clean the cache for the customers and lock all customers ...

                Debug($"Initializing tables for the customer '{customerId}' ...");

                Dictionary <string, Dictionary <int, Tuple <DSRecord, InformationRecord> > > currentCache = new Dictionary <string, Dictionary <int, Tuple <DSRecord, InformationRecord> > >(_tables.Count);
                _records[customerId] = currentCache; // replace the cache already existing

                foreach (KeyValuePair <string, DSTable> table in _tables)
                {
                    currentCache[table.Key] = new Dictionary <int, Tuple <DSRecord, InformationRecord> >();
                }
            }

            _mutex.Release(); // unlock critical section

            // Loading all data

            foreach (string area in _tables.Select(t => t.Value.Area).Distinct())
            {
                if (area == null)
                {
                    continue;
                }

                Debug($"Loading tables from the area '{area}' ...");

                try
                {
                    using (DatabaseContext currentContext = getDatabase(area))
                    {
                        // Load data into the current cache

                        foreach (KeyValuePair <string, DSTable> table in _tables.Where(t => t.Value.Area.Equals(area)))
                        {
                            Debug($"Loading table '{table.Key}' ...");

                            try
                            {
                                int nbRecords = 0;

                                // Load all records between the last tick and the new one (only for request successfully executed)

                                foreach (Tuple <DSRecord, InformationRecord> record in table.Value.ReadRecords(currentContext))
                                {
                                    if (record.Item2.CustomerId < 0)
                                    {
                                        foreach (int customerId in customerIds)
                                        {
                                            _records[customerId][table.Key][record.Item1.Id] = record;
                                        }
                                        nbRecords++;
                                    }
                                    else if (customerIds.IndexOf(record.Item2.CustomerId) >= 0)
                                    {
                                        _records[record.Item2.CustomerId][table.Key][record.Item1.Id] = record;
                                        nbRecords++;
                                    }
                                }

                                Info($"{nbRecords} records read into the table '{table.Key}' ...");

                                GC.Collect();
                            }
                            catch (System.Exception ex)
                            {
                                Exception($"Unable to initialize the cache for the table '{table.Key}'", ex);
                            }
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    Exception($"Unable to load the area {area}", ex);
                }
            }

            // Finalize the initialization of the cache for this customer

            foreach (int customerId in customerIds)
            {
                _tick[customerId] = GetTick(database, customerId);
                Info($"[{customerId}] Cache initialized in tick {_tick[customerId]}");
                Unlock(customerId);
            }
        }