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();
 }
예제 #2
0
        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());
        }
예제 #3
0
        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());
        }
예제 #4
0
    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);
    }
예제 #5
0
        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());
        }
예제 #6
0
        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());
        }
예제 #7
0
        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());
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }