private void BuildMappingTable() { //Get a new mapping table in memory _mappingTable = new Dictionary <object, List <object> >(); //connect to server and run distinct query var server = MappingFromColumn.TableInfo.Discover(DataAccessContext.DataLoad).Database.Server; var fromColumnName = MappingFromColumn.GetRuntimeName(); var toColumnName = MappingToColumn.GetRuntimeName(); //pull back all the data using (var con = server.GetConnection()) { con.Open(); var sql = GetMappingTableSql(); var cmd = server.GetCommand(sql, con); cmd.CommandTimeout = Timeout; var r = cmd.ExecuteReader(); while (r.Read()) { if (!_mappingTable.ContainsKey(r[fromColumnName])) { _mappingTable.Add(r[fromColumnName], new List <object>()); } _mappingTable[r[fromColumnName]].Add(r[toColumnName]); } } }
public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { var fromColumnName = MappingFromColumn.GetRuntimeName(); var toColumnName = MappingToColumn.GetRuntimeName(); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "About to build mapping table")); if (!toProcess.Columns.Contains(fromColumnName)) { throw new Exception("DataTable did not contain a field called '" + fromColumnName + "'"); } if (toProcess.Columns.Contains(toColumnName)) { throw new Exception("DataTable already contained a field '" + toColumnName + "'"); } if (_mappingTable == null) { BuildMappingTable(); } listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Mapping table resulted in " + _mappingTable.Count + " unique possible input values")); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Mapping table resulted in " + _mappingTable.Sum(kvp => kvp.Value.Count) + " unique possible output values")); //add the new column (the output column) toProcess.Columns.Add(toColumnName); int idxFrom = toProcess.Columns.IndexOf(fromColumnName); int idxTo = toProcess.Columns.IndexOf(toColumnName); int numberOfElementsPerRow = toProcess.Columns.Count; List <object[]> newRows = new List <object[]>(); List <DataRow> toDrop = new List <DataRow>(); foreach (DataRow row in toProcess.Rows) { var fromValue = row[idxFrom]; //if we don't have the key value if (!_mappingTable.ContainsKey(fromValue)) { if (CrashIfNoMappingsFound) { throw new KeyNotFoundException("Could not find mapping for " + fromValue); } else { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, "No mapping for '" + fromValue + "' dropping row")); toDrop.Add(row); continue; } } //we do have the key value! var results = _mappingTable[fromValue]; //yes 1 if (results.Count == 1) { row[idxTo] = results.Single(); } else { //great we have multiple mappings, bob=>Frank and bob=>Jesus. What does the user want to do about that switch (AliasResolutionStrategy) { case AliasResolutionStrategy.CrashIfAliasesFound: throw new AliasException("The value '" + fromValue + "' maps to mulitple ouptut values:" + string.Join(",", results.Select(v => "'" + v.ToString() + "'"))); case AliasResolutionStrategy.MultiplyInputDataRowsByAliases: //substitute for the first alias (bob=>Frank) row[idxTo] = results.First(); //then clone the row and do a row with bob=>Jesus foreach (object next in results.Skip(1)) { //Create a copy of the input row object[] newRow = new object[numberOfElementsPerRow]; row.ItemArray.CopyTo(newRow, 0); //Set the aliasable element to the alias newRow[idxTo] = next; //Add it to our new rows collection newRows.Add(newRow); } break; default: throw new ArgumentOutOfRangeException(); } } } //add any alias multiplication rows foreach (object[] newRow in newRows) { toProcess.Rows.Add(newRow); } //drop rows with missing identifiers foreach (DataRow dropRow in toDrop) { toProcess.Rows.Remove(dropRow); } if (!KeepInputColumnToo) { toProcess.Columns.Remove(fromColumnName); } return(toProcess); }