/// <summary> /// Sorts the vertices in topological order /// </summary> /// <returns>List of topological sorted vertices</returns> public List <Vertex> TopologicalSort(ColumnChanges columnChanges) { IPriorityQueue <Vertex> priorityQueue = new IntervalHeap <Vertex>(new VerticesComparer(Options, columnChanges)); var sortedVertices = new List <Vertex>(); var incomingEdges = new Dictionary <Vertex, int>(); foreach (var v in Vertices) { incomingEdges[v] = v.IngoingEdges().Count; if (incomingEdges[v] == 0) { priorityQueue.Add(v); } } while (!priorityQueue.IsEmpty) { Vertex v = priorityQueue.FindMin(); sortedVertices.Add(v); priorityQueue.DeleteMin(); foreach (var e in v.OutgoingEdges()) { incomingEdges[e.Destination]--; if (incomingEdges[e.Destination] == 0) { priorityQueue.Add(e.Destination); } } } return(sortedVertices); }
/// <summary> /// Check if a specific flag is set /// </summary> /// <param name="value">Flag to check</param> /// <returns>True if set, false if unset</returns> public bool IsSet(ColumnChanges value) { // If value is None, then the enum must be zero, since no other change could have happened if (value == ColumnChanges.None) { return(value == 0); } return((ColumnChanges & value) != 0); }
private void ModifyColumn(ColumnChanges columnChanges) { //数据类型 if (columnChanges.IsDbTypeChanged) { this.AddOperation(new AlterColumnType { CopyFromColumn = columnChanges.OldColumn, NewType = columnChanges.NewColumn.DataType, IsRequired = columnChanges.OldColumn.IsRequired, }); } //是否主键 if (columnChanges.IsPrimaryKeyChanged) { var column = columnChanges.NewColumn; if (column.IsPrimaryKey) { this.AddOperation(new AddPKConstraint { CopyFromColumn = column, }); } else { this.AddOperation(new RemovePKConstraint { CopyFromColumn = column, }); } } //可空性 if (columnChanges.IsRequiredChanged) { this.ModifyColumnRequired(columnChanges); } //外键 if (columnChanges.ForeignRelationChangeType != ChangeType.UnChanged) { this.ModifyColumnForeignConstraint(columnChanges); } }
private void GenerateOpertions(ColumnChanges columnChanges) { switch (columnChanges.ChangeType) { case ChangeType.Added: this.AddColumn(columnChanges.NewColumn); break; case ChangeType.Removed: this.RemoveColumn(columnChanges.OldColumn); break; case ChangeType.Modified: this.ModifyColumn(columnChanges); break; default: break; } }
private void ModifyColumnRequired(ColumnChanges columnChanges) { if (columnChanges.NewColumn.IsRequired) { if (columnChanges.OldColumn.IsForeignKey) { this.AddOperation(new AddNotNullConstraintFK { CopyFromColumn = columnChanges.NewColumn }); } else { this.AddOperation(new AddNotNullConstraint { CopyFromColumn = columnChanges.NewColumn }); } } else { if (columnChanges.OldColumn.IsForeignKey) { this.AddOperation(new RemoveNotNullConstraintFK { CopyFromColumn = columnChanges.NewColumn }); } else { this.AddOperation(new RemoveNotNullConstraint { CopyFromColumn = columnChanges.NewColumn }); } } }
private void ModifyColumnForeignConstraint(ColumnChanges columnChanges) { var value = columnChanges.ForeignRelationChangeType; switch (value) { case ChangeType.Added: this.AddOperation(new AddFKConstraint { CopyFromConstraint = columnChanges.NewColumn.ForeignConstraint }); break; case ChangeType.Removed: this.AddOperation(new RemoveFKConstraint { CopyFromConstraint = columnChanges.OldColumn.ForeignConstraint }); break; case ChangeType.Modified: //throw new NotSupportedException("暂时不支持外键修改。"); this.AddOperation(new RemoveFKConstraint { CopyFromConstraint = columnChanges.OldColumn.ForeignConstraint }); this.AddOperation(new AddFKConstraint { CopyFromConstraint = columnChanges.NewColumn.ForeignConstraint }); break; default: break; } }
/// <summary> /// Unset value flag in enum /// </summary> /// <param name="value">Flag to unset</param> public void Unset(ColumnChanges value) { ColumnChanges &= ~value; }
/// <summary> /// Set value flag in enum /// </summary> /// <param name="value">Flag to set</param> public void Set(ColumnChanges value) { ColumnChanges |= value; }
/// <summary> /// Invoke "fixing" function based on provided change /// </summary> /// <param name="g">Graph</param> /// <param name="v">Vertex to invoke on</param> /// <param name="c">Reference to change</param> /// <param name="change">Action to perform</param> /// <param name="affectedVertices">Vertices affected by an EDS change</param> public void InvokeMethod(Vertex v, ColumnMetaChange c, ColumnChanges change, List <Vertex> affectedVertices) { Attribute a = new Attribute(); if (change != ColumnChanges.Addition) { // If attribute isn't available, then it is safe to assume it isn't a part of the job, and won't affect any transformation if ((a = GetAttribute(c)) == null) { return; } // If the vertex is not affected by the change, we stop. if (!affectedVertices.Contains(v)) { return; } } else { a.Change(c); } // Invoke method on vertex based on the provided change. // We've already split the ColumnChanges enum into its components, so it is safe to switch on switch (change) { case ColumnChanges.None: break; case ColumnChanges.Addition: if (v.UsesAttribute(a)) { v.AdditionAttribute(this, a, c); } break; case ColumnChanges.Deletion: v.DeletionAttribute(this, a, c); break; case ColumnChanges.Rename: v.RenameAttribute(this, a, c); break; case ColumnChanges.DataType: v.DataTypeAttribute(this, a, c); break; case ColumnChanges.Length: break; case ColumnChanges.Nullable: break; case ColumnChanges.NonNull: break; case ColumnChanges.Unique: break; case ColumnChanges.NonUnique: break; case ColumnChanges.PrimaryKey: break; case ColumnChanges.NonPrimary: break; } }
/// <summary> /// Main algorithm used to perform alterations of graph given a ColumnMetaChange /// </summary> /// <param name="change">Change to perform in graph</param> public void Alter(ColumnMetaChange change, ColumnChanges changeType) { // if partial fix is not enabled quit if (Options.UseGlobalBlockingSemantics && Vertices.Any(v => Options.PolicyTable[changeType][v.GetType()] == Policy.BLOCK)) { return; } List <Vertex> sortedVertices = TopologicalSort(changeType); Logger.Debug("Order of fixing transformations:"); sortedVertices.ForEach(v => Logger.Debug(v.Name)); List <Vertex> affectedVertices = GetAffectedVertices(change); foreach (Vertex v in sortedVertices) { // Assumes partial fix is enabled. if (Options.PolicyTable[changeType][v.GetType()] == Policy.BLOCK) { Logger.Debug($"Blocked the propagation at {v.Name}"); break; } v.CleanUpDependencies(); // TODO: Insert Data type change fix/check here // Check for attributes that need to be deleted (and delete vertex if no attributes are left) if (!(v is OLEDBSource)) { foreach (Attribute a in v.OutputAttributes()) { // If no dependencies are found for a given attribute, then it is safe to delete if (v.Dependencies[a].Count == 0) { if (v.IsFullyDependent(a)) { RemoveVertex(v); break; } // If not, then just remove attribute else { v.RemoveOutputAttribute(a); v.CleanUpRemovedAttribute(a); } } } } // Since a destination in many scenarioes don't have any output edges, then this specific check is necessary if (v is OLEDBDestination && v.IngoingEdges().Count == 0) { RemoveVertex(v); } // If the vertex has not been removed, we continue if (Vertices.Contains(v)) { v.CleanUpInputCollection(); InvokeMethod(v, change, changeType, affectedVertices); } } }
public VerticesComparer(Options.Options options, ColumnChanges columnChange) { _options = options; _columnChange = columnChange; }