protected virtual IEnumerable <MigrationOperation> Remove([NotNull] IForeignKey source, [NotNull] DiffContext diffContext)
        {
            var declaringRootEntityType     = source.DeclaringEntityType.RootType();
            var sourceEntityTypeAnnotations = Annotations.For(declaringRootEntityType);

            var dropTableOperation = diffContext.FindDrop(declaringRootEntityType);

            if (dropTableOperation == null)
            {
                yield return(new DropForeignKeyOperation
                {
                    Schema = sourceEntityTypeAnnotations.Schema,
                    Table = sourceEntityTypeAnnotations.TableName,
                    Name = Annotations.For(source).Name
                });
            }
        }
        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());
        }