private IReadOnlyList<IEntityType> Sort(IReadOnlyList<IEntityType> entityTypes) { var entityTypeGraph = new Multigraph<IEntityType, int>(); entityTypeGraph.AddVertices(entityTypes); foreach (var entityType in entityTypes.Where(et => et.BaseType != null)) { entityTypeGraph.AddEdge(entityType.BaseType, entityType, 0); } return entityTypeGraph.TopologicalSort(); }
public void TopologicalSort_can_break_simple_cycle() { var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree }); // 1 -> {2} graph.AddEdge(vertexOne, vertexTwo, edgeOne); // 2 -> {3} graph.AddEdge(vertexTwo, vertexThree, edgeTwo); // 3 -> {1} graph.AddEdge(vertexThree, vertexOne, edgeThree); Assert.Equal( new[] { vertexOne, vertexTwo, vertexThree }, graph.TopologicalSort( (from, to, edges) => (@from == vertexThree) && (to == vertexOne) && (edges.Single() == edgeThree)).ToArray()); }
public void TopologicalSort_on_graph_with_no_edges_returns_all_verticies() { var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree }); var result = graph.TopologicalSort(); Assert.Equal(3, result.Count()); Assert.Equal(3, result.Intersect(new[] { vertexOne, vertexTwo, vertexThree }).Count()); }
public void TopologicalSort_throws_with_default_message_when_cycle_cannot_be_broken() { var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree }); // 1 -> {2} graph.AddEdge(vertexOne, vertexTwo, edgeOne); // 2 -> {3} graph.AddEdge(vertexTwo, vertexThree, edgeTwo); // 3 -> {1} graph.AddEdge(vertexThree, vertexOne, edgeThree); Assert.Equal( CoreStrings.CircularDependency( string.Join( " ->" + Environment.NewLine, new[] { vertexOne, vertexTwo, vertexThree, vertexOne }.Select(v => v.ToString()))), Assert.Throws <InvalidOperationException>(() => graph.TopologicalSort()).Message); }
public void TopologicalSort_on_tree_graph_returns_all_verticies_in_order() { var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree }); // 1 -> {2, 3} graph.AddEdge(vertexOne, vertexTwo, edgeOne); graph.AddEdge(vertexOne, vertexThree, edgeTwo); // 3 -> {2} graph.AddEdge(vertexThree, vertexTwo, edgeThree); Assert.Equal( new[] { vertexOne, vertexThree, vertexTwo }, graph.TopologicalSort().ToArray()); }
protected virtual IReadOnlyList <MigrationOperation> Sort([NotNull] IEnumerable <MigrationOperation> operations) { Check.NotNull(operations, nameof(operations)); var dropOperations = new List <MigrationOperation>(); var dropColumnOperations = new List <MigrationOperation>(); var dropTableOperations = new List <MigrationOperation>(); var dropSchemaOperations = new List <MigrationOperation>(); var createSchemaOperations = new List <MigrationOperation>(); var createSequenceOperations = new List <MigrationOperation>(); var createTableOperations = new Dictionary <string, CreateTableOperation>(); var alterOperations = new List <MigrationOperation>(); var renameOperations = new List <MigrationOperation>(); var renameIndexOperations = new List <MigrationOperation>(); var renameTableOperations = new List <MigrationOperation>(); var leftovers = new List <MigrationOperation>(); foreach (var operation in operations) { var type = operation.GetType(); if (_dropOperationTypes.Contains(type)) { dropOperations.Add(operation); } else if (type == typeof(DropColumnOperation)) { dropColumnOperations.Add(operation); } else if (type == typeof(DropTableOperation)) { dropTableOperations.Add(operation); } else if (type == typeof(DropSchemaOperation)) { dropSchemaOperations.Add(operation); } else if (type == typeof(CreateSchemaOperation)) { createSchemaOperations.Add(operation); } else if (type == typeof(CreateSequenceOperation)) { createSequenceOperations.Add(operation); } else if (type == typeof(CreateTableOperation)) { var createTableOperation = (CreateTableOperation)operation; createTableOperations.Add( createTableOperation.Schema + ":" + createTableOperation.Name, createTableOperation); } else if (_alterOperationTypes.Contains(type)) { alterOperations.Add(operation); } else if (_renameOperationTypes.Contains(type)) { renameOperations.Add(operation); } else if (type == typeof(RenameIndexOperation)) { renameIndexOperations.Add(operation); } else if (type == typeof(RenameTableOperation)) { renameTableOperations.Add(operation); } else { Debug.Assert(false, "Unexpected operation type: " + operation.GetType()); leftovers.Add(operation); } } var createTableGraph = new Multigraph <string, AddForeignKeyOperation>(); createTableGraph.AddVertices(createTableOperations.Keys); foreach (var pair in createTableOperations) { foreach (var addForeignKeyOperation in pair.Value.ForeignKeys) { var principalTable = addForeignKeyOperation.ReferencedSchema + ":" + addForeignKeyOperation.ReferencedTable; if (principalTable == pair.Key) { continue; } if (!createTableOperations.ContainsKey(principalTable)) { continue; } createTableGraph.AddEdge(principalTable, pair.Key, addForeignKeyOperation); } } var sortedCreateTableOperations = createTableGraph.TopologicalSort( (principalTable, key, foreignKeyOperations) => { foreach (var foreignKeyOperation in foreignKeyOperations) { createTableOperations[key].ForeignKeys.Remove(foreignKeyOperation); alterOperations.Add(foreignKeyOperation); } return(true); }) .Select(k => createTableOperations[k]); return(dropOperations .Concat(dropColumnOperations) .Concat(dropTableOperations) .Concat(dropSchemaOperations) .Concat(createSchemaOperations) .Concat(createSequenceOperations) .Concat(sortedCreateTableOperations) .Concat(alterOperations) .Concat(renameOperations) .Concat(renameIndexOperations) .Concat(renameTableOperations) .Concat(leftovers) .ToArray()); }
public void TopologicalSort_can_break_two_cycles() { var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var vertexFour = new Vertex { Id = 4 }; var vertexFive = new Vertex { Id = 5 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var edgeFour = new Edge { Id = 4 }; var edgeFive = new Edge { Id = 5 }; var edgeSix = new Edge { Id = 6 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree, vertexFour, vertexFive }); // 1 -> {2, 4} graph.AddEdge(vertexOne, vertexTwo, edgeOne); graph.AddEdge(vertexOne, vertexFour, edgeTwo); // 2 -> {3} graph.AddEdge(vertexTwo, vertexThree, edgeThree); // 3 -> {1} graph.AddEdge(vertexThree, vertexOne, edgeFour); // 4 -> {5} graph.AddEdge(vertexFour, vertexFive, edgeFive); // 5 -> {1} graph.AddEdge(vertexFive, vertexOne, edgeSix); Assert.Equal( new[] { vertexTwo, vertexThree, vertexOne, vertexFour, vertexFive }, graph.TopologicalSort( (from, to, edges) => { var edge = edges.Single(); return(edge == edgeOne || edge == edgeSix); }).ToArray()); }
public void BatchingTopologicalSort_throws_with_formatted_message_with_no_tail_when_cycle_cannot_be_broken() { const string message = "Formatted cycle"; var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var vertexFour = new Vertex { Id = 4 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var edgeFour = new Edge { Id = 4 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree, vertexFour }); // 2 -> {1} graph.AddEdge(vertexTwo, vertexOne, edgeOne); // 3 -> {2} graph.AddEdge(vertexThree, vertexTwo, edgeTwo); // 4 -> {3} graph.AddEdge(vertexFour, vertexThree, edgeThree); // 3 -> {4} graph.AddEdge(vertexThree, vertexFour, edgeFour); Dictionary <Vertex, Tuple <Vertex, Vertex, IEnumerable <Edge> > > cycleData = null; Func <IEnumerable <Tuple <Vertex, Vertex, IEnumerable <Edge> > >, string> formatter = data => { cycleData = data.ToDictionary(entry => entry.Item1); return(message); }; Assert.Equal( CoreStrings.CircularDependency(message), Assert.Throws <InvalidOperationException>(() => graph.BatchingTopologicalSort(formatter)).Message); Assert.Equal(2, cycleData.Count); Assert.Equal(vertexFour, cycleData[vertexThree].Item2); Assert.Equal(new[] { edgeFour }, cycleData[vertexThree].Item3); Assert.Equal(vertexThree, cycleData[vertexFour].Item2); Assert.Equal(new[] { edgeThree }, cycleData[vertexFour].Item3); }
private IEnumerable <IProperty> GetSortedProperties(IEntityType entityType) { var schema = _cassandraOptionsExtension.DefaultKeyspace; var shadowProperties = new List <IProperty>(); var shadowPrimaryKeyProperties = new List <IProperty>(); var primaryKeyPropertyGroups = new Dictionary <PropertyInfo, IProperty>(); var groups = new Dictionary <PropertyInfo, List <IProperty> >(); var unorderedGroups = new Dictionary <PropertyInfo, SortedDictionary <int, IProperty> >(); var types = new Dictionary <Type, SortedDictionary <int, PropertyInfo> >(); var model = entityType.Model; var declaredProperties = entityType.GetDeclaredProperties().ToList(); declaredProperties.AddRange(entityType.ClrType.GetProperties().Where(p => { var et = model.FindEntityType(p.PropertyType); if (et == null || !et.IsUserDefinedType()) { return(false); } return(true); }).Select(p => new Property(p.Name, p.PropertyType, null, null, entityType as EntityType, ConfigurationSource.Convention, null)).ToList()); foreach (var property in declaredProperties) { var clrProperty = property.PropertyInfo; if (clrProperty == null) { if (property.IsPrimaryKey()) { shadowPrimaryKeyProperties.Add(property); continue; } var foreignKey = property.GetContainingForeignKeys() .FirstOrDefault(fk => fk.DependentToPrincipal?.PropertyInfo != null); if (foreignKey == null) { shadowProperties.Add(property); continue; } clrProperty = foreignKey.DependentToPrincipal.PropertyInfo; var groupIndex = foreignKey.Properties.IndexOf(property); unorderedGroups.GetOrAddNew(clrProperty).Add(groupIndex, property); } else { if (property.IsPrimaryKey()) { primaryKeyPropertyGroups.Add(clrProperty, property); } groups.Add( clrProperty, new List <IProperty> { property }); } var clrType = clrProperty.DeclaringType; var index = clrType.GetTypeInfo().DeclaredProperties .IndexOf(clrProperty, PropertyInfoEqualityComparer.Instance); types.GetOrAddNew(clrType)[index] = clrProperty; } foreach (var group in unorderedGroups) { groups.Add(group.Key, group.Value.Values.ToList()); } foreach (var definingForeignKey in entityType.GetDeclaredReferencingForeignKeys() .Where( fk => fk.DeclaringEntityType.GetRootType() != entityType.GetRootType() && fk.DeclaringEntityType.GetTableName() == entityType.GetTableName() && fk.DeclaringEntityType.GetSchema() == schema && fk == fk.DeclaringEntityType .FindForeignKey( fk.DeclaringEntityType.FindPrimaryKey().Properties, entityType.FindPrimaryKey(), entityType))) { var clrProperty = definingForeignKey.PrincipalToDependent?.PropertyInfo; var properties = GetSortedProperties(definingForeignKey.DeclaringEntityType).ToList(); if (clrProperty == null) { shadowProperties.AddRange(properties); continue; } groups.Add(clrProperty, properties); var clrType = clrProperty.DeclaringType; var index = clrType.GetTypeInfo().DeclaredProperties .IndexOf(clrProperty, PropertyInfoEqualityComparer.Instance); types.GetOrAddNew(clrType)[index] = clrProperty; } var graph = new Multigraph <Type, object>(); graph.AddVertices(types.Keys); foreach (var left in types.Keys) { var found = false; foreach (var baseType in left.GetBaseTypes()) { foreach (var right in types.Keys) { if (right == baseType) { graph.AddEdge(right, left, null); found = true; break; } } if (found) { break; } } } var sortedPropertyInfos = graph.TopologicalSort().SelectMany(e => types[e].Values).ToList(); return(sortedPropertyInfos .Select(pi => primaryKeyPropertyGroups.ContainsKey(pi) ? primaryKeyPropertyGroups[pi] : null) .Where(e => e != null) .Concat(shadowPrimaryKeyProperties) .Concat(sortedPropertyInfos.Where(pi => !primaryKeyPropertyGroups.ContainsKey(pi)).SelectMany(p => groups[p])) .Concat(shadowProperties) .Concat(entityType.GetDirectlyDerivedTypes().SelectMany(GetSortedProperties))); }
protected virtual IReadOnlyList <MigrationOperation> Sort( [NotNull] IEnumerable <MigrationOperation> operations, [NotNull] DiffContext diffContext) { Check.NotNull(operations, nameof(operations)); var dropForeignKeyOperations = new List <MigrationOperation>(); var dropOperations = new List <MigrationOperation>(); var dropColumnOperations = new List <MigrationOperation>(); var dropTableOperations = new List <DropTableOperation>(); var ensureSchemaOperations = new List <MigrationOperation>(); var createSequenceOperations = new List <MigrationOperation>(); var createTableOperations = new List <CreateTableOperation>(); var alterOperations = new List <MigrationOperation>(); var renameOperations = new List <MigrationOperation>(); var renameIndexOperations = new List <MigrationOperation>(); var renameTableOperations = new List <MigrationOperation>(); var leftovers = new List <MigrationOperation>(); foreach (var operation in operations) { var type = operation.GetType(); if (type == typeof(DropForeignKeyOperation)) { dropForeignKeyOperations.Add(operation); } else if (_dropOperationTypes.Contains(type)) { dropOperations.Add(operation); } else if (type == typeof(DropColumnOperation)) { dropColumnOperations.Add(operation); } else if (type == typeof(DropTableOperation)) { dropTableOperations.Add((DropTableOperation)operation); } else if (type == typeof(EnsureSchemaOperation)) { ensureSchemaOperations.Add(operation); } else if (type == typeof(CreateSequenceOperation)) { createSequenceOperations.Add(operation); } else if (type == typeof(CreateTableOperation)) { createTableOperations.Add((CreateTableOperation)operation); } else if (_alterOperationTypes.Contains(type)) { alterOperations.Add(operation); } else if (_renameOperationTypes.Contains(type)) { renameOperations.Add(operation); } else if (type == typeof(RenameIndexOperation)) { renameIndexOperations.Add(operation); } else if (type == typeof(RenameTableOperation)) { renameTableOperations.Add(operation); } else { Debug.Assert(false, "Unexpected operation type: " + operation.GetType()); leftovers.Add(operation); } } var createTableGraph = new Multigraph <CreateTableOperation, AddForeignKeyOperation>(); createTableGraph.AddVertices(createTableOperations); foreach (var createTableOperation in createTableOperations) { foreach (var addForeignKeyOperation in createTableOperation.ForeignKeys) { if ((addForeignKeyOperation.Table == addForeignKeyOperation.PrincipalTable) && (addForeignKeyOperation.Schema == addForeignKeyOperation.PrincipalSchema)) { continue; } var principalCreateTableOperation = createTableOperations.FirstOrDefault( o => (o.Name == addForeignKeyOperation.PrincipalTable) && (o.Schema == addForeignKeyOperation.PrincipalSchema)); if (principalCreateTableOperation != null) { createTableGraph.AddEdge(principalCreateTableOperation, createTableOperation, addForeignKeyOperation); } } } createTableOperations = createTableGraph.TopologicalSort( (principalCreateTableOperation, createTableOperation, addForeignKeyOperations) => { foreach (var addForeignKeyOperation in addForeignKeyOperations) { createTableOperation.ForeignKeys.Remove(addForeignKeyOperation); alterOperations.Add(addForeignKeyOperation); } return(true); }).ToList(); var dropTableGraph = new Multigraph <DropTableOperation, IForeignKey>(); dropTableGraph.AddVertices(dropTableOperations); foreach (var dropTableOperation in dropTableOperations) { var entityType = diffContext.GetMetadata(dropTableOperation); foreach (var foreignKey in GetForeignKeysInHierarchy(entityType)) { var principalRootEntityType = foreignKey.PrincipalEntityType.RootType(); if (entityType == principalRootEntityType) { continue; } var principalDropTableOperation = diffContext.FindDrop(principalRootEntityType); if (principalDropTableOperation != null) { dropTableGraph.AddEdge(dropTableOperation, principalDropTableOperation, foreignKey); } } } var newDiffContext = new DiffContext(); dropTableOperations = dropTableGraph.TopologicalSort( (dropTableOperation, principalDropTableOperation, foreignKeys) => { dropForeignKeyOperations.AddRange(foreignKeys.SelectMany(c => Remove(c, newDiffContext))); return(true); }).ToList(); return(dropForeignKeyOperations .Concat(dropOperations) .Concat(dropColumnOperations) .Concat(dropTableOperations) .Concat(ensureSchemaOperations) .Concat(createSequenceOperations) .Concat(createTableOperations) .Concat(alterOperations) .Concat(renameOperations) .Concat(renameIndexOperations) .Concat(renameTableOperations) .Concat(leftovers) .ToArray()); }
// To avoid violating store constraints the modification commands must be sorted // according to these rules: // // 1. Commands adding rows or modifying the candidate key values (when supported) must precede // commands adding or modifying rows that will be referencing the former // 2. Commands deleting rows or modifying the foreign key values must precede // commands deleting rows or modifying the candidate key values (when supported) of rows // that are currently being referenced by the former // 3. Commands deleting rows or modifying the foreign key values must precede // commands adding or modifying the foreign key values to the same values // if foreign key is unique /// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected virtual IReadOnlyList<List<ModificationCommand>> TopologicalSort([NotNull] IEnumerable<ModificationCommand> commands) { var modificationCommandGraph = new Multigraph<ModificationCommand, IForeignKey>(); modificationCommandGraph.AddVertices(commands); // The predecessors map allows to populate the graph in linear time var predecessorsMap = CreateKeyValuePredecessorMap(modificationCommandGraph); AddForeignKeyEdges(modificationCommandGraph, predecessorsMap); var sortedCommands = modificationCommandGraph.BatchingTopologicalSort(data => { return string.Join(", ", data.Select(d => d.Item3.First())); }); return sortedCommands; }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override IReadOnlyList <MigrationOperation> Sort([NotNull] IEnumerable <MigrationOperation> operations, [NotNull] MigrationsModelDiffer.DiffContext diffContext) { Check.NotNull(operations, nameof(operations)); var dropForeignKeyOperations = new List <MigrationOperation>(); var dropOperations = new List <MigrationOperation>(); var dropColumnOperations = new List <MigrationOperation>(); var dropTableOperations = new List <DropTableOperation>(); var ensureSchemaOperations = new List <MigrationOperation>(); var createSequenceOperations = new List <MigrationOperation>(); var createTableOperations = new List <CreateTableOperation>(); var addColumnOperations = new List <MigrationOperation>(); var alterOperations = new List <MigrationOperation>(); var addForeignKeyOperations = new List <MigrationOperation>(); var renameColumnOperations = new List <MigrationOperation>(); var renameOperations = new List <MigrationOperation>(); var renameTableOperations = new List <MigrationOperation>(); var leftovers = new List <MigrationOperation>(); foreach (var operation in operations) { var type = operation.GetType(); if (type == typeof(DropForeignKeyOperation)) { dropForeignKeyOperations.Add(operation); } else if (_dropOperationTypes.Contains(type)) { dropOperations.Add(operation); } else if (type == typeof(DropColumnOperation)) { dropColumnOperations.Add(operation); } else if (type == typeof(DropTableOperation)) { dropTableOperations.Add((DropTableOperation)operation); } else if (type == typeof(EnsureSchemaOperation)) { ensureSchemaOperations.Add(operation); } else if (type == typeof(CreateSequenceOperation)) { createSequenceOperations.Add(operation); } else if (type == typeof(CreateTableOperation)) { createTableOperations.Add((CreateTableOperation)operation); } else if (type == typeof(AddColumnOperation)) { addColumnOperations.Add(operation); } else if (_alterOperationTypes.Contains(type)) { alterOperations.Add(operation); } else if (type == typeof(AddForeignKeyOperation)) { addForeignKeyOperations.Add(operation); } else if (type == typeof(RenameColumnOperation)) { renameColumnOperations.Add(operation); } else if (_renameOperationTypes.Contains(type)) { renameOperations.Add(operation); } else if (type == typeof(RenameTableOperation)) { renameTableOperations.Add(operation); } else { Debug.Assert(false, "Unexpected operation type: " + operation.GetType()); leftovers.Add(operation); } } var createTableGraph = new Multigraph <CreateTableOperation, AddForeignKeyOperation>(); createTableGraph.AddVertices(createTableOperations); foreach (var createTableOperation in createTableOperations) { foreach (var addForeignKeyOperation in createTableOperation.ForeignKeys) { if ((addForeignKeyOperation.Table == addForeignKeyOperation.PrincipalTable) && (addForeignKeyOperation.Schema == addForeignKeyOperation.PrincipalSchema)) { continue; } var principalCreateTableOperation = createTableOperations.FirstOrDefault( o => (o.Name == addForeignKeyOperation.PrincipalTable) && (o.Schema == addForeignKeyOperation.PrincipalSchema)); if (principalCreateTableOperation != null) { createTableGraph.AddEdge(principalCreateTableOperation, createTableOperation, addForeignKeyOperation); } } } createTableOperations = createTableGraph.TopologicalSort( (principalCreateTableOperation, createTableOperation, cyclicAddForeignKeyOperations) => { foreach (var cyclicAddForeignKeyOperation in cyclicAddForeignKeyOperations) { createTableOperation.ForeignKeys.Remove(cyclicAddForeignKeyOperation); addForeignKeyOperations.Add(cyclicAddForeignKeyOperation); } return(true); }).ToList(); var dropTableGraph = new Multigraph <DropTableOperation, IForeignKey>(); dropTableGraph.AddVertices(dropTableOperations); foreach (var dropTableOperation in dropTableOperations) { var entityType = diffContext.GetMetadata(dropTableOperation); foreach (var foreignKey in (IEnumerable <IForeignKey>)GetForeignKeysInHierarchyMi.Invoke(this, new object[] { entityType })) { var principalRootEntityType = foreignKey.PrincipalEntityType.RootType(); if (entityType == principalRootEntityType) { continue; } var principalDropTableOperation = diffContext.FindDrop(principalRootEntityType); if (principalDropTableOperation != null) { dropTableGraph.AddEdge(dropTableOperation, principalDropTableOperation, foreignKey); } } } var newDiffContext = new DiffContext(); dropTableOperations = dropTableGraph.TopologicalSort( (dropTableOperation, principalDropTableOperation, foreignKeys) => { dropForeignKeyOperations.AddRange(foreignKeys.SelectMany(c => Remove(c, newDiffContext))); return(true); }).ToList(); var ret = dropForeignKeyOperations .Concat(renameTableOperations) .Concat(renameOperations) .Concat(renameColumnOperations) .Concat(dropOperations) .Concat(dropColumnOperations) .Concat(dropTableOperations) .Concat(ensureSchemaOperations) .Concat(createTableOperations) .Concat(addColumnOperations) .Concat(alterOperations) .Concat(addForeignKeyOperations) .Concat(leftovers) .Concat(createSequenceOperations) .ToArray(); // Fixed #37 Renaming a table while adding a new field/column fails when updating the migration in the database. var rename = ret.Where(x => x is RenameTableOperation).ToList(); foreach (RenameTableOperation rto in rename) { var fix = ret.Where(x => !(x is RenameTableOperation)).ToList(); foreach (dynamic x in fix) { try { x.Table = x.Table.Replace(rto.Name, rto.NewName); } catch { } } } // Fixed Renaming a table will drop and re-create PK issue. ret = ret.Where(x => !(x is AddPrimaryKeyOperation && ret.Any(y => y is DropPrimaryKeyOperation && ((DropPrimaryKeyOperation)y).Table == ((AddPrimaryKeyOperation)x).Table)) && !(x is DropPrimaryKeyOperation && ret.Any(y => y is AddPrimaryKeyOperation && ((AddPrimaryKeyOperation)y).Table == ((DropPrimaryKeyOperation)x).Table))).ToArray(); return(ret); }