/// <summary> /// Takes an existing DataTable with a fixed schema and validates the columns read during <see cref="GetHeadersFromFile"/> against it making minor changes /// where appropriate to match the schema /// </summary> /// <param name="dt"></param> /// <param name="listener"></param> /// <returns></returns> public void MakeDataTableFitHeaders(DataTable dt, IDataLoadEventListener listener) { if (_state != State.AfterHeadersRead) { throw new Exception("Illegal state, data table cannot be created at state " + _state); } _state = State.AfterTableGenerated; StringBuilder ASCIIArt = new StringBuilder(); List <string> headersNotFound = new List <string>(); for (int index = 0; index < _headers.Length; index++) { ASCIIArt.Append("[" + index + "]"); if (dt.Columns.Contains(_headers[index])) //exact match { ASCIIArt.AppendLine(_headers[index] + ">>>" + _headers[index]); continue; } if (string.IsNullOrWhiteSpace(_headers[index])) //Empty column header, ignore it { ASCIIArt.AppendLine("Blank Column>>>IGNORED"); continue; } //if we are ignoring the header if (IgnoreColumnsList.Contains(_headers[index])) { ASCIIArt.AppendLine(_headers[index] + ">>>IGNORED"); continue; } //try replacing spaces with underscores if (dt.Columns.Contains(_headers[index].Replace(" ", "_"))) { string before = _headers[index]; _headers[index] = _headers[index].Replace(" ", "_"); ASCIIArt.AppendLine(before + ">>>" + _headers[index]); continue; } //try replacing spaces with nothing if (dt.Columns.Contains(_headers[index].Replace(" ", ""))) { string before = _headers[index]; _headers[index] = _headers[index].Replace(" ", ""); ASCIIArt.AppendLine(before + ">>>" + _headers[index]); continue; } ASCIIArt.AppendLine(_headers[index] + ">>>" + UnmatchedText); headersNotFound.Add(_headers[index]); } //now that we have adjusted the header names string[] unmatchedColumns = dt.Columns.Cast <DataColumn>() .Where(c => !_headers.Any(h => h != null && h.ToLower().Equals(c.ColumnName.ToLower()))) //get all columns in data table where there are not any with the same name .Select(c => c.ColumnName) .ToArray(); if (unmatchedColumns.Any()) { ASCIIArt.AppendLine(Environment.NewLine + "Unmatched Columns In DataTable:" + Environment.NewLine + string.Join(Environment.NewLine, unmatchedColumns)); } //if there is exactly 1 column found by the program and there are unmatched columns it is likely the user has selected the wrong separator if (_headers.Length == 1 && unmatchedColumns.Any()) { foreach (string commonSeparator in _commonSeparators) { if (_headers[0].Contains(commonSeparator)) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, "Your separator does not appear in the headers line of your file (" + _toLoad.File.Name + ") but the separator '" + commonSeparator + "' does... did you mean to set the Separator to '" + commonSeparator + "'? The headers line is:\"" + _headers[0] + "\"")); } } } listener.OnNotify(this, new NotifyEventArgs( headersNotFound.Any()?ProgressEventType.Error : ProgressEventType.Information, //information or warning if there are unrecognised field names "I will now tell you about how the columns in your file do or do not match the columns in your database, Matching flat file columns (or forced replacement headers) against database headers resulted in:" + Environment.NewLine + ASCIIArt)); //tell them about what columns match what if (headersNotFound.Any()) { throw new Exception("Could not find a suitable target column for flat file columns " + string.Join(",", headersNotFound) + " amongst database data table columns (" + string.Join(",", from DataColumn col in dt.Columns select col.ColumnName) + ")"); } }
/// <summary> /// Creates a new empty DataTable has only the columns found in the headers that were read during <see cref="GetHeadersFromFile"/> /// </summary> /// <param name="listener"></param> /// <returns></returns> public DataTable GetDataTableWithHeaders(IDataLoadEventListener listener) { if (_state != State.AfterHeadersRead) { throw new Exception("Illegal state, data table cannot be created at state " + _state); } _state = State.AfterTableGenerated; var dt = new DataTable(); List <string> duplicateHeaders = new List <string>(); List <DataColumn> unamedColumns = new List <DataColumn>(); //create a string column for each header - these will change type once we have read some data foreach (string header in _headers) { string h = header; //if we are ignoring this column if (h != null && IgnoreColumnsList.Contains(h.Trim())) { continue; //skip adding to dt } //watch for duplicate columns if (dt.Columns.Contains(header)) { if (_makeHeaderNamesSane) { h = MakeHeaderUnique(header, dt.Columns, listener, this); } else { duplicateHeaders.Add(header); continue; } } if (h.IsBasicallyNull()) { unamedColumns.Add(dt.Columns.Add(h)); } else //override type if (_explicitlyTypedColumns != null && _explicitlyTypedColumns.ExplicitTypesCSharp.ContainsKey(h)) { dt.Columns.Add(h, _explicitlyTypedColumns.ExplicitTypesCSharp[h]); } else { dt.Columns.Add(h); } } UnamedColumns = new ReadOnlyCollection <DataColumn>(unamedColumns); if (duplicateHeaders.Any()) { throw new FlatFileLoadException("Found the following duplicate headers in file '" + _toLoad.File + "':" + string.Join(",", duplicateHeaders)); } return(dt); }