/// <summary>
        /// Writes the attributes.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <param name="info">The info.</param>
        protected static void WriteAttributes(IEnumerable<ComponentValue> attributes, DataRetrievalInfoXS info)
        {
            // write  attributes
            foreach (var keyValuePair in attributes)
            {
                var componentEntity = keyValuePair.Key;
                var value = keyValuePair.Value;

                // SODIHD-1272 write optional attribute only if it is not empty.
                if (componentEntity.ComponentType != SdmxComponentType.Attribute || componentEntity.AttStatus != AssignmentStatus.Conditional || !string.IsNullOrEmpty(value))
                {
                    info.XSWriter.WriteAttributeValue(componentEntity.Id, value);
                }
            }
        }
        /// <summary>
        /// Conditionally write the dataset values.
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        protected static void WriteDataSet(MappedXsValues row, DataRetrievalInfoXS info)
        {
            if (row.StartedDataSet)
            {
                return;
            }

            foreach (var dataSetLevelDimension in row.DataSetLevelDimensionValues)
            {
                info.XSWriter.WriteDataSetKeyValue(dataSetLevelDimension.Key.Id, dataSetLevelDimension.Value);
            }

            WriteAttributes(row.DataSetLevelAttributeValues, info);

            row.StartedDataSet = true;
        }
        /// <summary>
        /// Write a primary measure observation
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        /// <returns>
        /// The number of observations stored. 
        /// </returns>
        protected override int WriteObservation(MappedXsValues row, DataRetrievalInfoXS info)
        {
            if (row.MeasureDimensionValue == null)
            {
                throw new InvalidOperationException("MappedXsValues.MeasureDimension is null");
            }

            string tag;
            if (info.XSMeasureCodeToConcept.TryGetValue(row.MeasureDimensionValue.Value, out tag))
            {
                return WriteObservation(row, tag, row.PrimaryMeasureValue.Value, info);
            }

            throw new InvalidOperationException(
                string.Format(CultureInfo.InvariantCulture, "Unknown measure code {0}", row.MeasureDimensionValue.Value));
        }
 /// <summary>
 /// Write a primary measure observation
 /// </summary>
 /// <param name="row">
 /// The map between components and their values 
 /// </param>
 /// <param name="info">
 /// The current Data Retrieval state 
 /// </param>
 /// <returns>
 /// The number of observations stored. 
 /// </returns>
 protected abstract int WriteObservation(MappedXsValues row, DataRetrievalInfoXS info);
        /// <summary>
        /// Write the CrossSectional Group with the dimensions and attributes found in <paramref name="row"/>
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        protected static void WriteSection(MappedXsValues row, DataRetrievalInfoXS info)
        {
            info.XSWriter.StartSection();

            foreach (var dimension in row.SectionLevelDimensionValues)
            {
                info.XSWriter.WriteSectionKeyValue(dimension.Key.Id, dimension.Value);
            }

            // write observation attributes
            WriteAttributes(row.SectionAttributeValues, info);
        }
        /// <summary>
        /// Write observation element. The time, observation and attribute values are in <paramref name="row"/>
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="tag">
        /// The element tag. The Primary or XS measure concept ref. 
        /// </param>
        /// <param name="value">
        /// The observation value 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        /// <returns>
        /// The number of observations stored. Is is always 1 
        /// </returns>
        protected static int WriteObservation(MappedXsValues row, string tag, string value, DataRetrievalInfoXS info)
        {
            // write time and obs value
            info.XSWriter.StartXSObservation(tag, value);

            // write observation attributes
            foreach (var keyValuePair in row.ObservationLevelDimensionValues)
            {
                info.XSWriter.WriteXSObservationKeyValue(keyValuePair.Key.Id, keyValuePair.Value);
            }

            // write observation attributes
            WriteAttributes(row.ObservationLevelAttributeValues, info);
            return 1;
        }
        /// <summary>
        /// Write the CrossSectional Group with the dimensions and attributes found in <paramref name="row"/>
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        protected static void WriteGroup(MappedXsValues row, DataRetrievalInfoXS info)
        {
            info.XSWriter.StartXSGroup();

            foreach (var groupLevelDimension in row.GroupLevelDimensionValues)
            {
                info.XSWriter.WriteXSGroupKeyValue(groupLevelDimension.Key.Id, groupLevelDimension.Value);
            }

            WriteAttributes(row.GroupLevelAttributeValues, info);
        }
        /// <summary>
        /// Write a primary measure observation
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        /// <param name="limit">
        /// The limit. 
        /// </param>
        /// <returns>
        /// The number of observations stored. 
        /// </returns>
        private static int WriteObservation(MappedXsValues row, DataRetrievalInfoXS info, int limit)
        {
            int maxMeasures = Math.Min(info.CrossSectionalMeasureMappings.Count, limit);

            int count = 0;
            for (var i = 0; i < maxMeasures; i++)
            {
                var crossSectionalMeasureMapping = info.CrossSectionalMeasureMappings[i];
                var xsComponent = crossSectionalMeasureMapping.Components[0];
                count += WriteObservation(row, xsComponent.Id, row.GetXSMeasureValue(xsComponent), info);
            }

            return count;
        }
        /// <summary>
        /// Write a primary measure observation
        /// </summary>
        /// <param name="row">
        /// The map between components and their values 
        /// </param>
        /// <param name="info">
        /// The current Data Retrieval state 
        /// </param>
        /// <returns>
        /// The number of observations stored. 
        /// </returns>
        protected override int WriteObservation(MappedXsValues row, DataRetrievalInfoXS info)
        {
            int count = 0;
            for (var i = 0; i < info.CrossSectionalMeasureMappings.Count; i++)
            {
                var crossSectionalMeasureMapping = info.CrossSectionalMeasureMappings[i];
                var xsComponent = crossSectionalMeasureMapping.Components[0];
                count += WriteObservation(row, xsComponent.Id, row.GetXSMeasureValue(xsComponent), info);
            }

            return count;
        }
        /// <summary>
        /// Retrieve data from a DDB and write it to the specified <paramref name="writer"/> This is the main public method of the DataRetriever class. It is called with a populated QueryBean (containing essentially an SDMX-ML Query) and a database Connection to a "Mapping Store" database. This method is responsible for: 
        /// <list type="bullet">
        /// <item>
        /// Retrieving the <see cref="MappingSetEntity"/> (the class containing the performed mappings), according to the provided Dataflow ID, from the "Mapping Store". Mapping Sets are defined on a Dataflow basis. Thus, this method checks the input QueryBean for the Dataflow that data are requested and fetches the appropriate
        /// <see cref="MappingSetEntity"/>. If no <see cref="MappingSetEntity"/> exists, an exception (<see cref="DataRetrieverException"/>) is thrown.
        /// </item>
        /// <item>
        /// Calling the method generating the appropriate SQL for the dissemination database.
        /// </item>
        /// <item>
        /// Calling the method that executes the generated SQL and uses the
        ///  <paramref name="writer"/>
        ///  to write the output.
        /// </item>
        /// </list>
        /// <note type="note">
        /// The "Data Retriever" expects exactly one Dataflow clause under the DataWhere clause, exactly one
        ///        DataFlowBean within the DataWhereBean (which in turn resides inside the incoming QueryBean).
        /// </note>
        /// </summary>
        /// <exception cref="DataRetrieverException">
        /// See the
        ///   <see cref="ErrorTypes"/>
        ///   for more details
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="query"/>
        ///   is null
        ///   -or-
        ///   <paramref name="writer"/>
        ///   is null
        /// </exception>
        /// <param name="query">
        /// The query bean for which data will be requested 
        /// </param>
        /// <param name="writer">
        /// The Cross Sectional writer 
        /// </param>
        /// <example>
        /// An example using this method in C# with <see cref="CrossSectionalWriter"/> 
        ///  <code source="ReUsingExamples\DataRetriever\ReUsingDataRetrieverCrossSectional.cs" lang="cs">
        /// </code>
        /// </example>
        public void GetData(IDataQuery dataQuery, ICrossSectionalWriterEngine dataWriter)
        {
            if (dataQuery == null)
            {
                throw new ArgumentNullException("query");
            }

            if (dataWriter == null)
            {
                throw new ArgumentNullException("writer");
            }

            try
            {
                Logger.Info(Resources.InfoDataRetrieverBBInvoked);
                Logger.Info(Resources.InfoOutput + dataWriter.GetType().Name);

                // validate input and initialize the mappingset entitiy
                MappingSetEntity mappingSet = this.Initialize(dataQuery);

                var info = new DataRetrievalInfoXS(mappingSet, dataQuery, this._connectionStringSettings, dataWriter)
                {
                    DefaultHeader = this._defaultHeader
                };
                ValidateMappingSet(info);
                this.WriteHeader(dataWriter, info);
                ICrossSectionalDataStructureObject crossDsd = dataQuery.DataStructure as ICrossSectionalDataStructureObject;

                //(SRA-345) 
                //DR the info from I*DataQuery. DimensionAtObservation to IDataWriterEngine.StartDataSet  
                IDatasetStructureReference dsr = new DatasetStructureReferenceCore("", dataQuery.DataStructure.AsReference, null, null, dataQuery.DimensionAtObservation);
                IDatasetHeader header = new DatasetHeaderCore(this._defaultHeader.DatasetId, this._defaultHeader.Action, dsr);

                dataWriter.StartDataset(dataQuery.Dataflow, crossDsd, header);

                this.GenerateSql(info, _sqlXsBuilder);

                // execute sql query.
                this.ExecuteSql(info, CrossSectionalQueryEngineManager.Instance.GetQueryEngine(info));

                // close output
                dataWriter.Close();
                Logger.Info(Resources.InfoEndDataRetrieverBBInvoked);
            }
            catch (DataRetrieverException)
            {
                throw;
            }
            catch (SdmxException)
            {
                throw;
            }
            catch (DbException ex)
            {
                Logger.Error(ex.ToString());
                throw new DataRetrieverException(ex,
                    SdmxErrorCode.GetFromEnum(SdmxErrorCodeEnumType.InternalServerError),
                    Resources.DataRetriever_ExecuteSqlQuery_Error_executing_generated_SQL_and_populating_SDMX_model);
                //ErrorTypes.DDB_CONNECTION_ERROR,
                //Resources.DataRetriever_ExecuteSqlQuery_Error_executing_generated_SQL_and_populating_SDMX_model,
                //ex);
            }
            catch (OutOfMemoryException)
            {
                throw;
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString());
                throw new DataRetrieverException(ex,
                    SdmxErrorCode.GetFromEnum(SdmxErrorCodeEnumType.InternalServerError),
                    Resources.DataRetriever_ExecuteSqlQuery_Error_during_writing_responce);
                //ErrorTypes.WRITING_OUTPUT_ERROR,
                //Resources.DataRetriever_ExecuteSqlQuery_Error_during_writing_responce,
                //ex);
            }
        }
 /// <summary>
 /// Write a primary measure observation
 /// </summary>
 /// <param name="row">
 /// The map between components and their values 
 /// </param>
 /// <param name="info">
 /// The current Data Retrieval state 
 /// </param>
 /// <returns>
 /// The number of observations stored. 
 /// </returns>
 protected override int WriteObservation(MappedXsValues row, DataRetrievalInfoXS info)
 {
     return WriteObservation(row, row.PrimaryMeasureValue.Key.Id, row.PrimaryMeasureValue.Value, info);
 }