public Dictionary <TableInfo, DiscoveredTable> GetIsolationTables() { var db = IsolationDatabase.Discover(DataAccessContext.InternalDataProcessing); return(TablesToIsolate.ToDictionary( tableInfo => tableInfo, tableInfo => db.ExpectTable(PrimaryKeyCollisionIsolationMutilation.GetIsolationTableName(tableInfo)) )); }
private void MigrateRecords(ColumnInfo deleteOn, string deleteValue) { var deleteOnColumnName = GetRAWColumnNameFullyQualified(deleteOn); using (var con = _raw.Server.GetConnection()) { con.Open(); //if we are deleting on a child table we need to look up the primary table primary key (e.g. StudyInstanceUID) we should then migrate that data instead (for all tables) if (!deleteOn.Equals(_primaryTablePk)) { var oldValue = deleteValue; deleteValue = GetPrimaryKeyValueFor(deleteOn, deleteValue, con); deleteOnColumnName = GetRAWColumnNameFullyQualified(_primaryTablePk); if (deleteValue == null) { throw new Exception("Primary key value not found for " + oldValue); } _job.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Corresponding primary key is '" + deleteValue + "' ('" + deleteOnColumnName + "')")); } //pull all records that we must isolate in all joined tables Dictionary <TableInfo, DataTable> toPush = new Dictionary <TableInfo, DataTable>(); foreach (TableInfo tableInfo in TablesToIsolate) { toPush.Add(tableInfo, PullTable(tableInfo, con, deleteOnColumnName, deleteValue)); } //push the results to isolation foreach (KeyValuePair <TableInfo, DataTable> kvp in toPush) { var toDatabase = IsolationDatabase.Discover(DataAccessContext.DataLoad); var toTable = toDatabase.ExpectTable(GetIsolationTableName(kvp.Key)); using (var bulkInsert = toTable.BeginBulkInsert()) bulkInsert.Upload(kvp.Value); } foreach (TableInfo t in TablesToIsolate.Reverse()) { DeleteRows(t, deleteOnColumnName, deleteValue, con); } } }
private void MigrateRecords(ColumnInfo deleteOn, object[] deleteValues) { var deleteOnColumnName = GetRAWColumnNameFullyQualified(deleteOn); using (var con = _raw.Server.GetConnection()) { con.Open(); //if we are deleting on a child table we need to look up the primary table primary key (e.g. StudyInstanceUID) we should then migrate that data instead (for all tables) if (!deleteOn.Equals(_primaryTablePk)) { deleteValues = GetPrimaryKeyValuesFor(deleteOn, deleteValues, con); deleteOnColumnName = GetRAWColumnNameFullyQualified(_primaryTablePk); } //pull all records that we must isolate in all joined tables Dictionary <TableInfo, DataTable> toPush = new Dictionary <TableInfo, DataTable>(); foreach (TableInfo tableInfo in TablesToIsolate) { toPush.Add(tableInfo, PullTable(tableInfo, con, deleteOnColumnName, deleteValues)); } //push the results to isolation foreach (KeyValuePair <TableInfo, DataTable> kvp in toPush) { var toDatabase = IsolationDatabase.Discover(DataAccessContext.DataLoad); var toTable = toDatabase.ExpectTable(GetIsolationTableName(kvp.Key)); using (var bulkInsert = toTable.BeginBulkInsert()) bulkInsert.Upload(kvp.Value); } foreach (TableInfo t in TablesToIsolate.Reverse()) { DeleteRows(t, deleteOnColumnName, deleteValues, con); } con.Close(); } }
public void Check(ICheckNotifier notifier) { //if there is only one or no tables that's fine (mandatory will check for null itself) if (TablesToIsolate == null) { throw new Exception("No tables have been selected"); } //make sure there is only one primary key per table and that it's a string foreach (TableInfo t in TablesToIsolate) { if (t.ColumnInfos.Count(c => c.IsPrimaryKey) != 1) { throw new Exception("Table '" + t + "' did not have exactly 1 IsPrimaryKey column"); } } //if there are multiple tables then we must know how to join them if (TablesToIsolate.Length > 1 && TablesToIsolate.Count(t => t.IsPrimaryExtractionTable) != 1) { var primaryTables = TablesToIsolate.Where(t => t.IsPrimaryExtractionTable).ToArray(); notifier.OnCheckPerformed( new CheckEventArgs( $"There are {TablesToIsolate.Length} tables to operate on but {primaryTables.Length} are marked IsPrimaryExtractionTable ({string.Join(",",primaryTables.Select(t=>t.Name))}). This should be set on a single top level table only e.g. Study", CheckResult.Fail)); } try { //if there are multiple tables we need to know how to join them on a 1 column to 1 basis BuildJoinOrder(true); } catch (Exception e) { notifier.OnCheckPerformed(new CheckEventArgs("Failed to build join order", CheckResult.Fail, e)); return; } //This is where we put the duplicate records var db = IsolationDatabase.Discover(DataAccessContext.DataLoad); if (!db.Exists()) { throw new Exception("IsolationDatabase did not exist"); } //Make sure the isolation tables exist and the schema matches RAW foreach (var tableInfo in TablesToIsolate) { var table = db.ExpectTable(GetIsolationTableName(tableInfo)); if (!table.Exists()) { bool fix = notifier.OnCheckPerformed( new CheckEventArgs("Isolation table '" + table.GetFullyQualifiedName() + "' did not exist", CheckResult.Fail, null, "Create isolation table?")); if (fix) { CreateIsolationTable(table, tableInfo); } else { throw new Exception("User rejected change"); } } else { ValidateIsolationTableSchema(table, tableInfo, notifier); } } }
private void BuildJoinOrder(bool isChecks) { _qb = new QueryBuilder(null, null); var memory = new MemoryRepository(); foreach (TableInfo t in TablesToIsolate) { _qb.AddColumn(new ColumnInfoToIColumn(memory, t.ColumnInfos.First())); } _primaryTable = TablesToIsolate.Length == 1 ? TablesToIsolate[0] : TablesToIsolate.Single(t => t.IsPrimaryExtractionTable); _primaryTablePk = _primaryTable.ColumnInfos.Single(c => c.IsPrimaryKey); _qb.PrimaryExtractionTable = _primaryTable; _qb.RegenerateSQL(); _joins = _qb.JoinsUsedInQuery ?? new List <JoinInfo>(); _fromSql = SqlQueryBuilderHelper.GetFROMSQL(_qb); if (!isChecks) { foreach (TableInfo tableInfo in TablesToIsolate) { _fromSql = _fromSql.Replace(tableInfo.GetFullyQualifiedName(), GetRAWTableNameFullyQualified(tableInfo)); } } if (_joins.Any(j => j.GetSupplementalJoins().Any())) { throw new Exception("Supplemental (2 column) joins are not supported when resolving multi table primary key collisions"); } //order the tables in order of dependency List <TableInfo> tables = new List <TableInfo>(); TableInfo next = _primaryTable; int overflow = 10; while (next != null) { tables.Add(next); var jnext = _joins.SingleOrDefault(j => j.PrimaryKey.TableInfo.Equals(next)); if (jnext == null) { break; } next = jnext.ForeignKey.TableInfo; if (overflow-- == 0) { throw new Exception("Joins resulted in a loop overflow"); } } TablesToIsolate = tables.ToArray(); }