/// <summary> /// Execute a command against a data source, mapping the data reader GetSchemaTable() result to an enumerable of record dictionaries. /// This method perfoms LAZY LOADING/DEFERRED EXECUTION. /// Note that THE DATA READER WILL NOT BE DISPOSED UPON ENUMERATION OR FOREACH BRANCH OUT. /// </summary> /// <param name="dbDataReader"> The target data reader. </param> /// <param name="recordsAffectedCallback"> Executed when the output count of records affected is available to return (post enumeration). </param> /// <returns> An enumerable of record dictionary instances, containing key/value pairs of schema metadata. </returns> public IEnumerable<IRecord> GetSchemaRecordsFromReader(DbDataReader dbDataReader, Action<int> recordsAffectedCallback) { ReadOnlyCollection<DbColumn> dbColumns; DbColumn dbColumn; PropertyInfo[] propertyInfos; PropertyInfo propertyInfo; Record record; int recordsAffected; string key; object value; OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): enter", typeof(AdoNetStreamingFascade).Name)); if ((object)dbDataReader == null) throw new ArgumentNullException(nameof(dbDataReader)); OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): before yield", typeof(AdoNetStreamingFascade).Name)); if (!dbDataReader.CanGetColumnSchema()) throw new NotSupportedException(string.Format("The connection command type '{0}' does not support schema access.", dbDataReader.GetType().FullName)); dbColumns = dbDataReader.GetColumnSchema(); { OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): use table", typeof(AdoNetStreamingFascade).Name)); if ((object)dbColumns != null) { for (int index = 0; index < dbColumns.Count; index++) { dbColumn = dbColumns[index]; propertyInfos = dbColumn.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty); record = new Record(); record.Context = dbColumn; if ((object)propertyInfos != null) { for (int i = 0; i < propertyInfos.Length; i++) { propertyInfo = propertyInfos[i]; if (propertyInfo.GetIndexParameters().Any()) continue; key = propertyInfo.Name; value = propertyInfo.GetValue(dbColumn); value = value.ChangeType<object>(); record.Add(key, value); } } OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): on yield", typeof(AdoNetStreamingFascade).Name)); yield return record; // LAZY PROCESSING INTENT HERE / DO NOT FORCE EAGER LOAD } } OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): dispose table", typeof(AdoNetStreamingFascade).Name)); } OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): after yield", typeof(AdoNetStreamingFascade).Name)); recordsAffected = dbDataReader.RecordsAffected; if ((object)recordsAffectedCallback != null) recordsAffectedCallback(recordsAffected); OnlyWhen._PROFILE_ThenPrint(string.Format("{0}::GetSchemaRecordsFromReader(...): leave", typeof(AdoNetStreamingFascade).Name)); }