/// <summary>
        /// Returns <see langword="true"/> if the request keys of <paramref name="dataSource"/> have changed,
        /// otherwise <see langword="false"/>.
        /// </summary>
        /// <param name="dataSource">The data source to interrogate.</param>
        /// <param name="postedData">The posted application data.</param>
        /// <param name="existingData">The saved application data.</param>
        /// <returns>
        /// <see langword="true"/> if the request keys of <paramref name="dataSource"/> have changed,
        /// otherwise <see langword="false"/>.
        /// </returns>
        private bool KeysHaveChanged(ProductDataSource dataSource, ApplicationData postedData, ApplicationData existingData)
        {
            if (existingData == null)
            {
                return true;
            }

            List<string> sourceFields = dataSource.RequestFieldMap.Where(map => map.MapType == MapType.Field).Select(map => map.Source).ToList();
            foreach (string sourceField in sourceFields)
            {
                string oldValue = existingData.GetValue<string>(sourceField);
                string newValue = postedData.GetValue<string>(sourceField);
                if (newValue != oldValue)
                {
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Determines the optimal page on which <paramref name="dataSource"/> should be run, by interrogating the
        /// <see cref="F:ResponseFieldMap"/> to find the earliest page which contains a mapped control,
        /// and returns the id of the optimal page.
        /// </summary>
        /// <param name="dataSource">The data source to interrogate.</param>
        /// <param name="pageList">The page list containing the full control definitions.</param>
        /// <returns>The id of the optimal page on which <paramref name="dataSource"/> should be run.</returns>
        private int DetermineOptimalPageId(ProductDataSource dataSource, PageList pageList)
        {
            const int defaultVal = int.MaxValue;
            Dictionary<string, int> controlPageIndexes = pageList.AccumulateControlPageIndexes();
            List<string> targetFields = dataSource.ResponseFieldMap.Select(map => map.Target).ToList();
            int min = defaultVal;
            foreach (string target in targetFields)
            {
                if (controlPageIndexes.Keys.Contains(target))
                {
                    min = Math.Min(controlPageIndexes[target], min);
                }
            }

            return min == defaultVal ? -1 : pageList[min].PageId;
        }