/// <summary> /// Gets all the records in the Excel file and converts each to <see cref="Type"/> T. /// </summary> /// <typeparam name="T">The <see cref="Type"/> of the record.</typeparam> /// <returns>An <see cref="IEnumerable{T}" /> of records.</returns> public IEnumerable <T> GetRecords <T>() { // Get the type of all the records var type = typeof(T); // Make sure it is mapped if (_configuration.Maps[type] == null) { _configuration.Maps.Add(_configuration.AutoMap(type)); } // First read the header record and parse it ReadRow(); ParseHeaderRecord(); // Create the function to read the records outside the inner loop Delegate parseRecord; try { parseRecord = GetParseRecordFunc(type); } catch (Exception ex) { ExceptionHelper.AddExceptionDataMessage(ex, type); throw; } // Read each record one at a time and yield it while (!IsEmptyRecord()) { T record; try { _currentIndex = -1; record = (T)parseRecord.DynamicInvoke(); _row++; } catch (Exception ex) { // Build the details about the error so it can be logged var details = new ExcelReadErrorDetails { Row = _row + 1, // Show 1 based row to the user Column = _currentIndex + 1, // Show 1 based column to the user FieldName = (from pair in _namedIndexes from index in pair.Value where index == _currentIndex select pair.Key).SingleOrDefault(), FieldValue = _sheet[_row, _currentIndex].Value, }; // Add the details to the exception ExceptionHelper.AddExceptionDataMessage(ex, type, details); // If we are ignoring errors, optionally call the callback and continue if (_configuration.IgnoreReadingExceptions) { _configuration.ReadingExceptionCallback?.Invoke(ex, details); _row++; continue; } throw; } yield return(record); } }
/// <summary> /// Writes the list of typed records to the Excel file. /// </summary> /// <param name="records">The list of records to write.</param> public void WriteRecords <T>( IEnumerable <T> records) where T : class { // Get the type of all the records var type = typeof(T); // Make sure it is mapped if (_configuration.Maps[type] == null) { _configuration.Maps.Add(_configuration.AutoMap(type)); } // Get a list of all the properties so they will be sorted properly. var properties = new ExcelPropertyMapCollection(); AddProperties(properties, _configuration.Maps[type]); if (properties.Count == 0) { throw new ExcelWriterException($"No properties are mapped for type '{type.FullName}'."); } // Write the header WriteHeader(properties); // Write all the column styles WriteColumnStyles(properties); // Get the action method for writing the records out Delegate writeRecord = null; try { writeRecord = GetWriteRecordAction(type, properties); } catch (Exception ex) { ExceptionHelper.AddExceptionDataMessage(ex, type); throw; } // Now process each record foreach (var record in records) { writeRecord.DynamicInvoke(record); NextRecord(); } }
/// <summary> /// Gets all the records in the Excel file and converts each to <see cref="Type"/> T. /// </summary> /// <typeparam name="T">The <see cref="Type"/> of the record.</typeparam> /// <returns>An <see cref="IEnumerable{T}" /> of records.</returns> public IEnumerable <T> GetRecords <T>() { // Get the type of all the records var type = typeof(T); // Make sure it is mapped if (_configuration.Maps[type] == null) { _configuration.Maps.Add(_configuration.AutoMap(type)); } // First read the header record and parse it ParseHeaderRecord(); // Create the function to read the records outside the inner loop Delegate parseRecord; try { parseRecord = GetParseRecordFunc(type); } catch (Exception ex) { ExceptionHelper.AddExceptionDataMessage(ex, type); throw; } // Read each record one at a time and yield it var ignoreEmptyRows = Configuration.IgnoreEmptyRows; while (_reader.Read()) { // If we are not ignoring empty records, bail when we reach one. Otherwise we process all rows in the file. if (IsEmptyRecord()) { if (ignoreEmptyRows) { _row++; continue; } else { break; } } T record; try { _currentIndex = -1; record = (T)parseRecord.DynamicInvoke(); _row++; } catch (Exception ex) { // Build the details about the error so it can be logged var details = new ExcelReadErrorDetails { Row = _row + 1, // Show 1 based row to the user Column = _currentIndex + 1, // Show 1 based column to the user FieldName = (from pair in _namedIndexes from index in pair.Value where index == _currentIndex select pair.Key).SingleOrDefault(), FieldValue = _reader.GetValue(_currentIndex), }; // Use the inner exception if we have one so the message is more clear ex = ex.InnerException ?? ex; // Add the details to the exception ExceptionHelper.AddExceptionDataMessage(ex, type, details); // If we are ignoring errors, optionally call the callback and continue if (_configuration.IgnoreReadingExceptions) { _configuration.ReadingExceptionCallback?.Invoke(ex, details); _row++; continue; } throw; } yield return(record); } }