Esempio n. 1
0
        public virtual void ProcessRecord(TDomain domain, ImportValueDictionary <TDomain> values, bool isNew)
        {
            List <Exception> exceptions = new List <Exception>();

            foreach (var prop in Properties.Where(x => !x.IsIgnoredFor(domain)))
            {
                if (prop != _idProperty && (prop.Update || isNew))
                {
                    try
                    {
                        prop.SetValue(domain, isNew, values.Get(prop), Context, values);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                }
            }

            if (exceptions.Any())
            {
                throw new AggregateException(exceptions);
            }
        }
Esempio n. 2
0
 public abstract void SetValue(TDomain record, bool isNew, object value, TContext context, ImportValueDictionary <TDomain> values);
Esempio n. 3
0
 public virtual TDomain CreateRecord(ImportValueDictionary <TDomain> values)
 {
     return(Activator.CreateInstance <TDomain>());
 }
Esempio n. 4
0
        public void ImportFromDataTable(ImportType importType, DataTable dt, bool isFromExcel)
        {
            var import = this;

            Func <DataRow, IImportProperty, string> formatRowNumber = (dr, prop) =>
            {
                if (import.ByCellReference)
                {
                    return(prop?.Description == null ? null : (" for '" + prop.Description + "'"));
                }
                else
                {
                    int row = import.RowStart + dt.Rows.IndexOf(dr) + 1;
                    if (isFromExcel)
                    {
                        row++;              //Account for header row
                    }
                    if (import is IHasMetadataRow <TDomain> )
                    {
                        row++;
                    }

                    return($" for {(isFromExcel ? "row" : "record")} {row}");
                }
            };

            List <DataRow> rows = import.Sort(dt).ToList();

            Dictionary <DataRow, ImportValueDictionary <TDomain> > valuesDict = new Dictionary <DataRow, ImportValueDictionary <TDomain> >();

            //Parse the values
            foreach (DataRow dr in rows)
            {
                var values = new ImportValueDictionary <TDomain>();
                foreach (var prop in import.Properties)
                {
                    object val = dr[prop.FieldName];
                    if (val == DBNull.Value)
                    {
                        val = null;
                    }

                    //Data table stores nullable Enum as int. Have to convert it to the underlying enum type
                    if (Nullable.GetUnderlyingType(prop.PropertyType)?.IsEnum == true && val != null)
                    {
                        val = Enum.ToObject(Nullable.GetUnderlyingType(prop.PropertyType), val);
                    }

                    values[prop.ExpressionKey] = prop.Parse(val);
                }
                valuesDict[dr] = values;
            }

            import.BeforeImport(valuesDict.Values);

            var exceptions      = new List <Exception>();
            var importedRecords = new List <ImportedRecord <TDomain> >();

            foreach (DataRow dr in rows)
            {
                //skip rows that are all null
                if (dr.Table.Columns.OfType <DataColumn>().All(c => dr.IsNull(c)))
                {
                    continue;
                }

                try
                {
                    var values = valuesDict[dr];

                    TId  id       = import.CanUpdate ? values.Get(IdExpression) : default(TId);
                    bool idIsNull = EqualityComparer <TId> .Default.Equals(id, default(TId));

                    //Validate the import type
                    if (idIsNull && importType == ImportType.Update)
                    {
                        exceptions.Add(new Exception($"Valiation failed{formatRowNumber(dr, null)}: Attempting to update a non-existing record."));
                    }
                    else if (!idIsNull && importType == ImportType.Create)
                    {
                        exceptions.Add(new Exception($"Valiation failed{formatRowNumber(dr, null)}: Attempting to create an existing record."));
                    }

                    //Don't continue to validate this record if there are errors at this point.
                    if (exceptions.Any())
                    {
                        continue;
                    }

                    //Get the domain object
                    TDomain domain = null;
                    if (!idIsNull)
                    {
                        domain = FindById(id);
                    }
                    else
                    {
                        domain = import.CreateRecord(values);
                    }

                    bool isNew = EqualityComparer <TId> .Default.Equals(GetId(domain), default(TId));

                    //Validate required properties
                    foreach (var prop in import.Properties.Where(x => !x.IsIgnoredFor(domain)))
                    {
                        if (prop.Update || isNew) //Do not validate properties if they will not be updated and this is an update import
                        {
                            if (prop.Required && values.Get(prop) == null)
                            {
                                exceptions.Add(new Exception($"Validation failed{formatRowNumber(dr, prop)}: {prop.FieldName} is missing."));
                            }
                        }
                    }

                    //Validate Regex
                    foreach (var prop in import.Properties.Where(x => x.ValidateRegex != null && !x.IsIgnoredFor(domain)))
                    {
                        string str = values.Get(prop)?.ToString();
                        if (str != null)
                        {
                            if (!prop.ValidateRegex.IsMatch(str))
                            {
                                exceptions.Add(new Exception($"Validation failed{formatRowNumber(dr, prop)}: {prop.FieldName} must match /{prop.ValidateRegex}/"));
                            }
                        }
                    }

                    //Don't process this record if there are validation errors at this point.
                    if (exceptions.Any())
                    {
                        continue;
                    }

                    BeforeProcessRecord(domain);

                    //Process the row
                    import.ProcessRecord(domain, values, isNew);

                    //Validate the resulting record
                    try
                    {
                        //Validate conditionally required properties
                        foreach (var prop in import.Properties.Where(x => x.RequiredIf != null && !x.IsIgnoredFor(domain)))
                        {
                            if (prop.RequiredIf(domain) && values.Get(prop) == null)
                            {
                                exceptions.Add(new Exception($"Validation failed{formatRowNumber(dr, prop)}: {prop.FieldName} is missing."));
                            }
                        }

                        import.ValidateRecord(domain);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(new Exception($"Validation failed{formatRowNumber(dr, null)}: {ex.Message}", ex));
                    }

                    importedRecords.Add(new ImportedRecord <TDomain>()
                    {
                        Record = domain, Values = values, IsNew = isNew
                    });
                }
                catch (Exception ex)
                {
                    string messages = ex.Message;
                    if (ex is AggregateException ae)
                    {
                        messages = string.Join("; ", ae.InnerExceptions.Select(x => x.Message));
                    }
                    exceptions.Add(new Exception($"Import failed{formatRowNumber(dr, null)}: {messages}", ex));
                }
            }

            if (exceptions.Any())
            {
                throw new AggregateException(exceptions);
            }

            import.AfterImport(new AfterImportArgs <TDomain>(importedRecords, importType));
        }