예제 #1
0
        private void AddCellValidators <T>(IExcelToEnumerableOptions <T> options)
        {
            if (options.Validations == null)
            {
                return;
            }
            foreach (var item in options.Validations)
            {
                var cellSetter = _cellSettersDictionaryForRead.Values.FirstOrDefault(x =>
                                                                                     x.ColumnName?.ToLowerInvariant() == item.Key.ToLowerInvariant());
                if (cellSetter == null)
                {
                    continue;
                }
                if (cellSetter.Validators == null)
                {
                    cellSetter.Validators = new List <ExcelCellValidator>();
                }

                foreach (var validator in item.Value)
                {
                    cellSetter.Validators.Add(validator);
                }
            }
        }
예제 #2
0
        private bool CheckForMissingFields <T>(IExcelToEnumerableOptions <T> options, List <string> fieldsPresentInRow,
                                               int rowCount, IList <Exception> exceptionsList)
        {
            var diff    = options.LoweredRequiredColumns.Except(fieldsPresentInRow);
            var success = !diff.Any();

            if (!success)
            {
                var firstException = CreateExceptionForMissingField(diff.First(), rowCount);
                switch (options.ExceptionHandlingBehaviour)
                {
                case ExceptionHandlingBehaviour.ThrowOnFirstException:
                    throw firstException;

                default:
                    exceptionsList.Add(firstException);
                    foreach (var exception in diff.Skip(1).Select(x => CreateExceptionForMissingField(x, rowCount)))
                    {
                        exceptionsList.Add(exception);
                    }

                    break;
                }
            }

            return(success);
        }
예제 #3
0
        public RowMapper GetRowMapper <T>(IExcelToEnumerableOptions <T> options)
        {
            var hashCode = options.GetHashCode();

            return(_rowMapperDictionary.ContainsKey(hashCode)
                ? _rowMapperDictionary[hashCode]
                : null);
        }
예제 #4
0
        internal IEnumerable <T> MapExcelToEnumerable(string filePath,
                                                      IExcelToEnumerableContext excelToEnumerableContext,
                                                      IExcelToEnumerableOptions <T> options)
        {
            var workbook = new ExcelReader(filePath);
            var list     = MapWorkbookToEnumerable(workbook, excelToEnumerableContext, options);

            return(list);
        }
        public static void Ignore <T>(string propertyName, IExcelToEnumerableOptions <T> options)
        {
            if (options.UnmappedProperties == null)
            {
                options.UnmappedProperties = new List <string>();
            }

            options.UnmappedProperties.Add(propertyName);
        }
        internal static void MapsToColumnNumber <T>(int i, string propertyName, IExcelToEnumerableOptions <T> options)
        {
            if (i < 1)
            {
                throw new ExcelToEnumerableConfigException(
                          $"Unable to map '{propertyName}' to column {i}. MapsToColumnNumber expects a 1-based column number");
            }

            options.CustomHeaderNumbers[propertyName] = i - 1;
        }
예제 #7
0
        private RowMapper CreateRowMapperFromPropertyDescriptorCollection <T>(
            IExcelToEnumerableOptions <T> options)
        {
            var type        = typeof(T);
            var constructor = new RowMapper
            {
                Setters = GetSetters(type, options),
            };

            return(constructor);
        }
예제 #8
0
 private void GetPropertySetterDictionary <T>(IExcelToEnumerableOptions <T> options,
                                              string[] normalisedHeaderArray)
 {
     if (normalisedHeaderArray == null)
     {
         _cellSettersDictionaryForRead = GetPropertySetterDictionaryByColumnNumber(options.CustomHeaderNumbers, Setters);
     }
     else
     {
         ValidateColumnNames(GetNormalisedColumnNames(Setters), normalisedHeaderArray, options.UnmappedProperties, options.OptionalColumns, options.IgnoreColumnsWithoutMatchingProperties);
         GetPropertySetterDictionaryByColumnName(normalisedHeaderArray);
     }
 }
예제 #9
0
        private Func <object, object> GetPropertyMapping <T>(IExcelToEnumerableOptions <T> options,
                                                             string propertyName, Type typeOrEnumerableType)
        {
            if (options.CustomMappings.ContainsKey(propertyName))
            {
                return(options.CustomMappings[propertyName]);
            }

            if (DefaultTypeMappers.Dictionary.ContainsKey(typeOrEnumerableType))
            {
                return(DefaultTypeMappers.Dictionary[typeOrEnumerableType]);
            }
            return(typeOrEnumerableType.GetTypeWithoutNullable().IsEnum ? DefaultTypeMappers.CreateEnumTypeMapper(typeOrEnumerableType) : null);
        }
예제 #10
0
        public RowMapper SetRowMapper <T>(IExcelToEnumerableOptions <T> options)
        {
            var hashCode = options.GetHashCode();

            if (_rowMapperDictionary.ContainsKey(hashCode))
            {
                return(_rowMapperDictionary[hashCode]);
            }

            var rowMapper = CreateRowMapperFromPropertyDescriptorCollection(options);

            _rowMapperDictionary.TryAdd(hashCode, rowMapper);
            return(rowMapper);
        }
예제 #11
0
        private IEnumerable <PropertySetter> GetSetters <T>(Type type, IExcelToEnumerableOptions <T> options)
        {
            var propertyDescriptorCollection = TypeDescriptor.GetProperties(type);
            var propertyDescriptors          = propertyDescriptorCollection.Cast <PropertyDescriptor>().ToArray();

            if (options.UnmappedProperties != null)
            {
                propertyDescriptors = propertyDescriptors.Where(x => !options.UnmappedProperties.Contains(x.Name)).ToArray();
            }

            return(propertyDescriptors.Select(x =>
                                              GetSettersForProperty(type.GetProperty(x.Name), Array.IndexOf(propertyDescriptors.ToArray(), x), options))
                   .SelectMany(y => y).ToArray());
        }
예제 #12
0
        private IEnumerable <PropertySetter> GetSettersForProperty <T>(PropertyInfo propertyInfo, int index,
                                                                       IExcelToEnumerableOptions <T> options)
        {
            if (propertyInfo.PropertyType != typeof(string) &&
                typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType))
            {
                if (options.CollectionConfigurations == null ||
                    !options.CollectionConfigurations.ContainsKey(propertyInfo.Name))
                {
                    return(new PropertySetter[0]);
                }

                return(GetSettersForEnumerable(propertyInfo, index, options));
            }

            var setter = GetterSetterHelpers.GetSetter(propertyInfo);
            var getter = options.UniqueProperties != null && options.UniqueProperties.Contains(propertyInfo.Name)
                ? GetterSetterHelpers.GetGetter(propertyInfo)
                : null;
            var fromCellSetter = new PropertySetter
            {
                Getter     = getter,
                Setter     = setter,
                Type       = propertyInfo.PropertyType,
                ColumnName =
                    options.CustomHeaderNames != null && options.CustomHeaderNames.ContainsKey(propertyInfo.Name)
                        ? options.CustomHeaderNames[propertyInfo.Name]
                        : propertyInfo.Name.ToLowerInvariant(),
                PropertyName          = propertyInfo.Name,
                PropertyMapping       = GetPropertyMapping(options, propertyInfo.Name, propertyInfo.PropertyType),
                RelaxedNumberMatching = options.RelaxedNumberMatching && propertyInfo.PropertyType.IsNumeric()
            };

            if (propertyInfo.Name == options.RowNumberProperty)
            {
                fromCellSetter.ColumnName = null;
            }

            if (options.NotNullProperties.Contains(propertyInfo.Name))
            {
                fromCellSetter.Validators = new List <ExcelCellValidator> {
                    ExcelCellValidatorFactory.CreateRequired()
                };
            }

            return(new[] { fromCellSetter });
        }
예제 #13
0
        private IDictionary <int, string> ReadHeader(IExcelToEnumerableOptions <T> options, SheetReader worksheet)
        {
            IDictionary <int, string> header = null;

            if (options.UseHeaderNames || _options.OnReadingHeaderRowAction != null)
            {
                header = GetHeaderRow(worksheet);
                _options.OnReadingHeaderRowAction?.Invoke(header);
            }

            while (worksheet.CurrentRowNumber < options.StartRow)
            {
                worksheet.ReadNext();
            }

            return(header);
        }
예제 #14
0
        private IEnumerable <PropertySetter> GetSettersForEnumerable <T>(PropertyInfo propertyInfo, int index,
                                                                         IExcelToEnumerableOptions <T> options)
        {
            var collectionsConfig = options.CollectionConfigurations[propertyInfo.Name];
            var isDictionary      = typeof(IDictionary).IsAssignableFrom(propertyInfo.PropertyType);
            var enumerableType    = propertyInfo.PropertyType.GenericTypeArguments[0];
            var fromCellSetters   = collectionsConfig.ColumnNames.Select(x => new PropertySetter
            {
                ColumnName   = x.ToLowerInvariant(),
                PropertyName = propertyInfo.Name,
                Setter       = isDictionary
                    ? GetterSetterHelpers.GetDictionaryAdder(propertyInfo, x)
                    : GetterSetterHelpers.GetAdder(propertyInfo),
                Type            = enumerableType,
                PropertyMapping = GetPropertyMapping(options, propertyInfo.Name, enumerableType)
            });

            return(fromCellSetters);
        }
예제 #15
0
        private IEnumerable <T> MapWorkbookToEnumerable(ExcelReader workbook,
                                                        IExcelToEnumerableContext excelToEnumerableContext,
                                                        IExcelToEnumerableOptions <T> options)
        {
            _options = options;
            var worksheet = _options.WorksheetNumber.HasValue
                ? workbook[_options.WorksheetNumber.Value]
                : workbook[_options.WorksheetName];

            while (!worksheet.CurrentRowNumber.HasValue || worksheet.CurrentRowNumber < _options.HeaderRow)
            {
                worksheet.ReadNext();
            }

            _exceptionList =
                options.ExceptionHandlingBehaviour == ExceptionHandlingBehaviour.ThrowOnFirstException
                    ? null
                    : new List <Exception>();

            var rowMapper = excelToEnumerableContext.GetRowMapper(_options) ??
                            excelToEnumerableContext.SetRowMapper(_options);

            var headerArray   = ReadHeader(options, worksheet);
            var headerHandler = new HeaderHandler(rowMapper.Setters);
            var cellSettersDictionaryForRead = headerHandler.GetPropertySetterDictionary(headerArray, options);

            var list = MainLoop(worksheet, rowMapper, options, cellSettersDictionaryForRead);

            if (_options.UniqueProperties != null)
            {
                list = CheckUniqueFields(rowMapper, list);
            }

            HandleAggregatedExceptions();

            return(list);
        }
예제 #16
0
        private void HandleException <T>(
            object cellValue,
            string propertyName,
            int rowNumber,
            int columnNumber,
            IExcelToEnumerableOptions <T> options,
            IList <Exception> exceptionsList,
            Exception innerException,
            ExcelToEnumerableValidationCode?validationCode,
            string validationMessage = null)
        {
            var exception = new ExcelToEnumerableCellException(_currentObject, rowNumber, columnNumber, cellValue,
                                                               propertyName, RowValuesByColumRef, validationMessage, innerException, validationCode);

            switch (options.ExceptionHandlingBehaviour)
            {
            case ExceptionHandlingBehaviour.ThrowOnFirstException:
                throw exception;

            default:
                exceptionsList.Add(exception);
                break;
            }
        }
예제 #17
0
        internal IEnumerable <T> MapExcelToEnumerable(Stream excelStream,
                                                      ExcelToEnumerableContext excelToEnumerableContext, IExcelToEnumerableOptions <T> options)
        {
            var workbook = new ExcelReader(excelStream);
            var list     = MapWorkbookToEnumerable(workbook, excelToEnumerableContext, options);

            excelStream.Dispose();
            return(list);
        }
예제 #18
0
        private IEnumerable <T> MainLoop(SheetReader worksheet, RowMapper rowMapper,
                                         IExcelToEnumerableOptions <T> options, IDictionary <int, PropertySetter> cellSettersDictionaryForRead)
        {
            rowMapper.SetCellSettersDictionaryForRead(cellSettersDictionaryForRead);
            var list = new List <T>();

            do
            {
                if (_options.EndRow < 0 && worksheet.WorksheetDimension == null)
                {
                    throw new NotImplementedException("ExcelToEnumerable is currently unable to handle a negative EndingWithRow value for a worksheet that does not have a WorksheetDimension xml element.");
                }
                if (_options.EndRow < 0 && worksheet.WorksheetDimension != null)
                {
                    if (worksheet.CurrentRowNumber > worksheet.WorksheetDimension.BottomRight.Row + _options.EndRow)
                    {
                        break;
                    }
                }
                if (_options.EndRow >= 0 && worksheet.CurrentRowNumber > _options.EndRow)
                {
                    break;
                }

                rowMapper.ReadRowValues(worksheet);
                // ReSharper disable once PossibleInvalidOperationException
                var rowNumber = worksheet.CurrentRowNumber.Value;
                if (rowNumber <= options.HeaderRow)
                {
                    continue;
                }
                switch (options.BlankRowBehaviour)
                {
                case BlankRowBehaviour.CreateEntity:
                    var newEntities = HandleCreateEntityBehaviour(worksheet, rowMapper);
                    list.AddRange(newEntities);
                    break;

                case BlankRowBehaviour.Ignore:
                    var item = HandleIgnoreBehaviour(rowMapper, rowNumber);
                    if (item != null)
                    {
                        list.Add(item);
                    }
                    break;

                case BlankRowBehaviour.StopReading:
                    // ReSharper disable once IdentifierTypo
                    var continu =
                        HandleStopReadingOrThrowExceptionBehaviour(worksheet, list, rowMapper);
                    if (!continu)
                    {
                        return(list);
                    }
                    break;

                case BlankRowBehaviour.ThrowException:
                    var addedRow =
                        HandleStopReadingOrThrowExceptionBehaviour(worksheet, list, rowMapper);
                    if (!addedRow)
                    {
                        throw new ExcelToEnumerableRowException(
                                  null,
                                  $"Blank row found at row: '{rowNumber}'", rowNumber,
                                  rowMapper.RowValuesByColumRef);
                    }
                    break;
                }

                rowMapper.Clear();
            } while (worksheet.ReadNext());

            return(list);
        }
예제 #19
0
        public void CreateMapper <T>(IExcelToEnumerableOptions <T> options)
        {
            var fromRowConstructor = CreateRowMapperFromPropertyDescriptorCollection(options);

            _rowMapperDictionary.TryAdd(options.GetHashCode(), fromRowConstructor);
        }
 public static void NotNullProperties <T>(string propertyName, IExcelToEnumerableOptions <T> options)
 {
     options.NotNullProperties.Add(propertyName);
 }
 public static void Unique <T>(string propertyName, IExcelToEnumerableOptions <T> options)
 {
     options.UniqueProperties.Add(propertyName);
 }
 internal static void RequiredColumn <T>(bool isRequired, string propertyName, IExcelToEnumerableOptions <T> options)
 {
     if (isRequired)
     {
         options.ExplicitlyRequiredColumns.Add(propertyName);
     }
     else
     {
         options.ExplicitlyRequiredColumns.Remove(propertyName);
     }
 }
예제 #23
0
        public bool AddPropertiesFromRowValues <T>(object obj, int rowCount, IExcelToEnumerableOptions <T> options,
                                                   IList <Exception> exceptionsList)
        {
            _currentObject = obj;
            var           success = true;
            List <string> fieldsPresentInThisRow = (options.NotNullProperties != null && options.NotNullProperties.Any())
                ? new List <string>()
                : null;

            foreach (var item in RowValues)
            {
                var cellValue              = item.Value;
                var propertySetter         = _cellSettersDictionaryForRead[item.Key];
                var isRequiredAlreadyAdded = false;
                var invalidCast            = false;

                try
                {
                    cellValue = propertySetter.PropertyMapping != null
                        ? propertySetter.PropertyMapping(cellValue)
                        : ConvertType(cellValue, propertySetter.Type, propertySetter.RelaxedNumberMatching);

                    propertySetter.Setter(obj, cellValue);
                }
                catch (Exception e)
                {
                    if (propertySetter.PropertyMapping == null && !(e is InvalidCastException))
                    {
                        throw;
                    }

                    HandleException(cellValue, propertySetter.ColumnName, rowCount, item.Key, options,
                                    exceptionsList, e, null, "Value is invalid");
                    success     = false;
                    invalidCast = true;
                }

                if (propertySetter.Validators != null && !invalidCast)
                {
                    foreach (var validator in propertySetter.Validators)
                    {
                        if (!validator.Validator(cellValue))
                        {
                            HandleException(cellValue, propertySetter.ColumnName, rowCount, item.Key, options,
                                            exceptionsList, null,
                                            validator.ExcelToEnumerableValidationCode,
                                            validator.Message);
                            if (validator.ExcelToEnumerableValidationCode == ExcelToEnumerableValidationCode.Required)
                            {
                                isRequiredAlreadyAdded = true;
                            }

                            success = false;
                            break;
                        }
                    }
                }

                if (fieldsPresentInThisRow != null && !isRequiredAlreadyAdded)
                {
                    fieldsPresentInThisRow.Add(propertySetter.ColumnName);
                }
            }

            if (fieldsPresentInThisRow != null)
            {
                var result = CheckForMissingFields(options, fieldsPresentInThisRow, rowCount, exceptionsList);
                if (!result)
                {
                    success = false;
                }
            }

            if (options.RowNumberProperty != null)
            {
                var setter = Setters.First(x => x.PropertyName == options.RowNumberProperty);
                setter.Setter(obj, rowCount);
            }

            return(success);
        }
예제 #24
0
        public IDictionary <int, PropertySetter> GetPropertySetterDictionary <T>(IDictionary <int, string> headers, IExcelToEnumerableOptions <T> options)
        {
            var normalisedHeaderArray = headers?.Values.Select(x => x?.ToNormalisedVariableName()).ToArray();

            GetPropertySetterDictionary(options, normalisedHeaderArray);
            AddCellValidators(options);
            return(_cellSettersDictionaryForRead);
        }
        internal static void MapFromColumns <T>(IEnumerable <string> columnNames, string propertyName, IExcelToEnumerableOptions <T> options)
        {
            if (options.CollectionConfigurations == null)
            {
                options.CollectionConfigurations = new Dictionary <string, ExcelToEnumerableCollectionConfiguration>();
            }

            var configuration = new ExcelToEnumerableCollectionConfiguration
            {
                PropertyName = propertyName,
                ColumnNames  = columnNames
            };

            options.CollectionConfigurations.Add(propertyName, configuration);
        }
 public static void MapsToColumnNamed <T>(string columnName, string propertyName, IExcelToEnumerableOptions <T> options)
 {
     options.CustomHeaderNames[propertyName] = columnName;
 }
 public static void ShouldBeGreaterThan <T>(double minValue, string propertyName, IExcelToEnumerableOptions <T> options)
 {
     if (!options.Validations.ContainsKey(propertyName))
     {
         options.Validations[propertyName] = new List <ExcelCellValidator>();
     }
     options.Validations[propertyName].Add(ExcelCellValidatorFactory.CreateGreaterThan(minValue));
 }
 public static void MapsToRowNumber <T>(string propertyName, IExcelToEnumerableOptions <T> options)
 {
     options.RowNumberProperty = propertyName;
 }