public IReadOnlyCollection <CmsSetting> Handle(AllConfigCmsSettingsQuery query)
        {
            // Using Kentico's InfoProvider, ObjectQuery, DataQuery, ConnectionHelper all result in calls to get appSettings, infinite loops and stack overflows - so we will use ADO.NET directly

            string prefix = query.Prefix ?? string.Empty;

            const string keyNamePrefixParam = "@KeyNamePrefix";

            var sqlQuery = new SqlQuery(
                query.ProcName,
                CommandType.StoredProcedure,
                new []
            {
                new SqlQueryParameter(keyNamePrefixParam, $"{prefix}%")
            }
                );

            return(sqlQueryExecutor.ExecuteReader(
                       sqlQuery,
                       ConnectionHelper.DEFAULT_CONNECTIONSTRING_NAME,
                       dataReader => new CmsSetting(
                           dataReader.GetString(0),
                           dataReader.GetString(1),
                           dataReader.GetString(2),
                           dataReader.GetString(3)
                           )
                       ));
        }
        public ICollection <KeyValuePair <string, string> > GetAllValues(string prefix)
        {
            var values = new Dictionary <string, string>();

            try
            {
                // Get all settings

                var query = new AllConfigCmsSettingsQuery(options.ProcName, prefix);
                IReadOnlyCollection <CmsSetting> settings = allSettingsQueryHandler.Handle(query);

                // Group settings by site (global settings represented by an empty string) so we can split up processing

                const string globalSiteName = "";

                var settingsBySite = settings.GroupBy(setting => setting.SiteName ?? globalSiteName)
                                     .ToDictionary(group => group.Key, group => group.ToList());

                // Add global settings first as these are a straight-forward add

                List <CmsSetting> globalSettings = settingsBySite[globalSiteName];

                foreach (CmsSetting setting in globalSettings)
                {
                    AddSetting(setting, values);
                }

                // Group global settings by category - these will be used as default values for site settings

                const string nullCategoryName = "";

                var globalSettingsByCategory = globalSettings
                                               .GroupBy(setting => setting.CategoryName ?? nullCategoryName)
                                               .ToDictionary(group => group.Key, group => group.ToList());

                // Now add site settings

                foreach (string siteName in settingsBySite.Keys)
                {
                    if (siteName == globalSiteName)
                    {
                        // We have already added global settings so continue

                        continue;
                    }

                    // We will add one category at a time and fallback to global values for any related category setting that is not set at site level - this is done to make it easier to get config settings by section (category)

                    var siteSettingsByCategory = settingsBySite[siteName]
                                                 .GroupBy(setting => setting.CategoryName ?? nullCategoryName)
                                                 .ToDictionary(group => group.Key, group => group.ToList());

                    foreach (string categoryName in siteSettingsByCategory.Keys)
                    {
                        List <CmsSetting> categoryGlobalSettings = globalSettingsByCategory[categoryName];
                        List <CmsSetting> categorySiteSettings   = siteSettingsByCategory[categoryName];

                        foreach (CmsSetting globalSetting in categoryGlobalSettings)
                        {
                            // There may not be a site setting present for each global setting in the category - if there is not add the setting with the global value; if there is add the setting with the site value

                            CmsSetting siteSetting = categorySiteSettings.FirstOrDefault(setting => setting.Name == globalSetting.Name);

                            var categorySetting = new CmsSetting(
                                globalSetting.Name,
                                siteSetting == null ? globalSetting.Value : siteSetting.Value,
                                categoryName,
                                siteName
                                );

                            AddSetting(categorySetting, values);
                        }
                    }
                }
            }
            catch (Exception)
            {
                if (!options.Optional)
                {
                    throw;
                }
            }

            return(values);
        }