private void WriteIndexParameters(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
        {
            if (createIndexOperation.IsUnique)
            {
                writer.Write(", unique := True");
            }

            if (createIndexOperation.IsClustered)
            {
                writer.Write(", clustered := True");
            }

            if (!createIndexOperation.HasDefaultName)
            {
                writer.Write(", name := ");
                writer.Write(Quote(createIndexOperation.Name));
            }
        }
        /// <summary>
        /// Generates code to specify a set of column names using a lambda expression.
        /// </summary>
        /// <param name="columns"> The columns to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(IEnumerable<string> columns, IndentedTextWriter writer)
        {
            Check.NotNull(columns, "columns");
            Check.NotNull(writer, "writer");

            writer.Write("Function(t) ");

            if (columns.Count() == 1)
            {
                writer.Write("t." + ScrubName(columns.Single()));
            }
            else
            {
                writer.Write("New With { " + columns.Join(c => "t." + ScrubName(c)) + " }");
            }
        }
        /// <summary>
        /// Generates code to perform a <see cref="DropForeignKeyOperation" />.
        /// </summary>
        /// <param name="dropForeignKeyOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(DropForeignKeyOperation dropForeignKeyOperation, IndentedTextWriter writer)
        {
            Check.NotNull(dropForeignKeyOperation, "dropForeignKeyOperation");
            Check.NotNull(writer, "writer");

            writer.Write("DropForeignKey(");
            writer.Write(Quote(dropForeignKeyOperation.DependentTable));
            writer.Write(", ");

            if (!dropForeignKeyOperation.HasDefaultName)
            {
                writer.Write(Quote(dropForeignKeyOperation.Name));
            }
            else
            {
                var compositeKey = dropForeignKeyOperation.DependentColumns.Count() > 1;

                if (compositeKey)
                {
                    writer.Write("New String() { ");
                }

                writer.Write(dropForeignKeyOperation.DependentColumns.Join(Quote));

                if (compositeKey)
                {
                    writer.Write(" }");
                }

                writer.Write(", ");
                writer.Write(Quote(dropForeignKeyOperation.PrincipalTable));
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform an <see cref="AddPrimaryKeyOperation" /> as part of a <see cref="CreateTableOperation" />.
        /// </summary>
        /// <param name="addPrimaryKeyOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void GenerateInline(AddPrimaryKeyOperation addPrimaryKeyOperation, IndentedTextWriter writer)
        {
            Check.NotNull(writer, "writer");

            if (addPrimaryKeyOperation != null)
            {
                writer.WriteLine(" _");
                writer.Write(".PrimaryKey(");

                Generate(addPrimaryKeyOperation.Columns, writer);

                if (!addPrimaryKeyOperation.HasDefaultName)
                {
                    writer.Write(", name := ");
                    writer.Write(Quote(addPrimaryKeyOperation.Name));
                }

                if (!addPrimaryKeyOperation.IsClustered)
                {
                    writer.Write(", clustered := False");
                }

                writer.Write(")");
            }
        }
        /// <summary>
        /// Generates code to perform a <see cref="CreateIndexOperation" /> as part of a <see cref="CreateTableOperation" />.
        /// </summary>
        /// <param name="createIndexOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void GenerateInline(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
        {
            Check.NotNull(createIndexOperation, "createIndexOperation");
            Check.NotNull(writer, "writer");

            writer.WriteLine(" _");
            writer.Write(".Index(");
            Generate(createIndexOperation.Columns, writer);
            WriteIndexParameters(createIndexOperation, writer);
            writer.Write(")");
        }
        protected virtual void Generate(ParameterModel parameterModel, IndentedTextWriter writer, bool emitName = false)
        {
            Check.NotNull(parameterModel, "parameterModel");
            Check.NotNull(writer, "writer");

            writer.Write(" p.");
            writer.Write(TranslateColumnType(parameterModel.Type));
            writer.Write("(");

            var args = new List<string>();

            if (emitName)
            {
                args.Add("name := " + Quote(parameterModel.Name));
            }

            if (parameterModel.MaxLength != null)
            {
                args.Add("maxLength := " + parameterModel.MaxLength);
            }

            if (parameterModel.Precision != null)
            {
                args.Add("precision := " + parameterModel.Precision);
            }

            if (parameterModel.Scale != null)
            {
                args.Add("scale := " + parameterModel.Scale);
            }

            if (parameterModel.IsFixedLength != null)
            {
                args.Add("fixedLength := " + parameterModel.IsFixedLength.ToString().ToLowerInvariant());
            }

            if (parameterModel.IsUnicode != null)
            {
                args.Add("unicode := " + parameterModel.IsUnicode.ToString().ToLowerInvariant());
            }

            if (parameterModel.DefaultValue != null)
            {
                args.Add("defaultValue := " + Generate((dynamic)parameterModel.DefaultValue));
            }

            if (!string.IsNullOrWhiteSpace(parameterModel.DefaultValueSql))
            {
                args.Add("defaultValueSql := " + Quote(parameterModel.DefaultValueSql));
            }

            if (!string.IsNullOrWhiteSpace(parameterModel.StoreType))
            {
                args.Add("storeType := " + Quote(parameterModel.StoreType));
            }

            if (parameterModel.IsOutParameter)
            {
                args.Add("outParameter := True");
            }

            writer.Write(args.Join());
            writer.Write(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="CreateTableOperation" />.
        /// </summary>
        /// <param name="createTableOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(CreateTableOperation createTableOperation, IndentedTextWriter writer)
        {
            Check.NotNull(createTableOperation, "createTableOperation");
            Check.NotNull(writer, "writer");

            writer.WriteLine("CreateTable(");
            writer.Indent++;
            writer.Write(Quote(createTableOperation.Name));
            writer.WriteLine(",");
            writer.WriteLine("Function(c) New With");
            writer.Indent++;
            writer.WriteLine("{");
            writer.Indent++;

            var columnCount = createTableOperation.Columns.Count();

            createTableOperation.Columns.Each(
                (c, i) =>
                {
                    var scrubbedName = ScrubName(c.Name);

                    writer.Write(".");
                    writer.Write(scrubbedName);
                    writer.Write(" =");
                    Generate(c, writer, !string.Equals(c.Name, scrubbedName, StringComparison.Ordinal));

                    if (i < columnCount - 1)
                    {
                        writer.Write(",");
                    }

                    writer.WriteLine();
                });

            writer.Indent--;
            writer.Write("}");
            writer.Indent--;

            if (createTableOperation.Annotations.Any())
            {
                writer.WriteLine(",");
                writer.Write("annotations := ");
                GenerateAnnotations(createTableOperation.Annotations, writer);
            }

            writer.Write(")");

            GenerateInline(createTableOperation.PrimaryKey, writer);

            _newTableForeignKeys
                .Where(t => t.Item1 == createTableOperation)
                .Each(t => GenerateInline(t.Item2, writer));

            _newTableIndexes
                .Where(t => t.Item1 == createTableOperation)
                .Each(t => GenerateInline(t.Item2, writer));

            writer.WriteLine();
            writer.Indent--;
            writer.WriteLine();
        }
        /// <summary>
        /// Generates code to perform a <see cref="RenameIndexOperation" />.
        /// </summary>
        /// <param name="renameIndexOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(RenameIndexOperation renameIndexOperation, IndentedTextWriter writer)
        {
            Check.NotNull(renameIndexOperation, "renameIndexOperation");
            Check.NotNull(writer, "writer");

            writer.Write("RenameIndex(table := ");
            writer.Write(Quote(renameIndexOperation.Table));
            writer.Write(", name := ");
            writer.Write(Quote(renameIndexOperation.Name));
            writer.Write(", newName := ");
            writer.Write(Quote(renameIndexOperation.NewName));
            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="SqlOperation" />.
        /// </summary>
        /// <param name="sqlOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(SqlOperation sqlOperation, IndentedTextWriter writer)
        {
            Check.NotNull(sqlOperation, "sqlOperation");
            Check.NotNull(writer, "writer");

            writer.Write("Sql(");
            writer.Write(Quote(sqlOperation.Sql));

            if (sqlOperation.SuppressTransaction)
            {
                writer.Write(", suppressTransaction := True");
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="MoveProcedureOperation" />.
        /// </summary>
        /// <param name="moveProcedureOperation">The operation to generate code for.</param>
        /// <param name="writer">Text writer to add the generated code to.</param>
        protected virtual void Generate(MoveProcedureOperation moveProcedureOperation, IndentedTextWriter writer)
        {
            Check.NotNull(moveProcedureOperation, "moveProcedureOperation");
            Check.NotNull(writer, "writer");

            writer.Write("MoveStoredProcedure(name := ");
            writer.Write(Quote(moveProcedureOperation.Name));
            writer.Write(", newSchema := ");
            writer.Write(
                string.IsNullOrWhiteSpace(moveProcedureOperation.NewSchema)
                    ? "Nothing"
                    : Quote(moveProcedureOperation.NewSchema));
            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="RenameProcedureOperation" />.
        /// </summary>
        /// <param name="renameProcedureOperation">The operation to generate code for.</param>
        /// <param name="writer">Text writer to add the generated code to.</param>
        protected virtual void Generate(RenameProcedureOperation renameProcedureOperation, IndentedTextWriter writer)
        {
            Check.NotNull(renameProcedureOperation, "renameProcedureOperation");
            Check.NotNull(writer, "writer");

            writer.Write("RenameStoredProcedure(name := ");
            writer.Write(Quote(renameProcedureOperation.Name));
            writer.Write(", newName := ");
            writer.Write(Quote(renameProcedureOperation.NewName));
            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="DropTableOperation" />.
        /// </summary>
        /// <param name="dropTableOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(DropTableOperation dropTableOperation, IndentedTextWriter writer)
        {
            Check.NotNull(dropTableOperation, "dropTableOperation");
            Check.NotNull(writer, "writer");

            writer.Write("DropTable(");
            writer.Write(Quote(dropTableOperation.Name));

            if (dropTableOperation.RemovedAnnotations.Any())
            {
                writer.Indent++;

                writer.WriteLine(",");
                writer.Write("removedAnnotations := ");
                GenerateAnnotations(dropTableOperation.RemovedAnnotations, writer);
                writer.Indent--;
            }

            var columns = dropTableOperation.RemovedColumnAnnotations;
            if (columns.Any())
            {
                writer.Indent++;

                writer.WriteLine(",");
                writer.Write("removedColumnAnnotations := ");

                writer.WriteLine("New Dictionary(Of String, IDictionary(Of String, Object)) From _");
                writer.WriteLine("{");
                writer.Indent++;

                var columnNames = columns.Keys.OrderBy(k => k).ToArray();
                for (var i = 0; i < columnNames.Length; i++)
                {
                    writer.WriteLine("{");
                    writer.Indent++;
                    writer.WriteLine(Quote(columnNames[i]) + ",");
                    GenerateAnnotations(columns[columnNames[i]], writer);
                    writer.WriteLine();
                    writer.Indent--;
                    writer.WriteLine(i < columnNames.Length - 1 ? " }," : " }");
                }

                writer.Indent--;
                writer.Write("}");
                writer.Indent--;
            }

            writer.WriteLine(")");
        }
        protected virtual void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
        {
            Check.NotNull(column, "column");
            Check.NotNull(writer, "writer");

            writer.Write(" c.");
            writer.Write(TranslateColumnType(column.Type));
            writer.Write("(");

            var args = new List<string>();

            if (emitName)
            {
                args.Add("name := " + Quote(column.Name));
            }

            if (column.IsNullable == false)
            {
                args.Add("nullable := False");
            }

            if (column.MaxLength != null)
            {
                args.Add("maxLength := " + column.MaxLength);
            }

            if (column.Precision != null)
            {
                args.Add("precision := " + column.Precision);
            }

            if (column.Scale != null)
            {
                args.Add("scale := " + column.Scale);
            }

            if (column.IsFixedLength != null)
            {
                args.Add("fixedLength := " + column.IsFixedLength.ToString().ToLowerInvariant());
            }

            if (column.IsUnicode != null)
            {
                args.Add("unicode := " + column.IsUnicode.ToString().ToLowerInvariant());
            }

            if (column.IsIdentity)
            {
                args.Add("identity := True");
            }

            if (column.DefaultValue != null)
            {
                args.Add("defaultValue := " + Generate((dynamic)column.DefaultValue));
            }

            if (!string.IsNullOrWhiteSpace(column.DefaultValueSql))
            {
                args.Add("defaultValueSql := " + Quote(column.DefaultValueSql));
            }

            if (column.IsTimestamp)
            {
                args.Add("timestamp := True");
            }

            if (!string.IsNullOrWhiteSpace(column.StoreType))
            {
                args.Add("storeType := " + Quote(column.StoreType));
            }

            writer.Write(args.Join());

            if (column.Annotations.Any())
            {
                writer.Indent++;

                writer.WriteLine(args.Any() ? "," : "");
                writer.Write("annotations := ");
                GenerateAnnotations(column.Annotations, writer);

                writer.Indent--;
            }
            
            writer.Write(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="DropIndexOperation" />.
        /// </summary>
        /// <param name="dropIndexOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(DropIndexOperation dropIndexOperation, IndentedTextWriter writer)
        {
            Check.NotNull(dropIndexOperation, "dropIndexOperation");
            Check.NotNull(writer, "writer");

            writer.Write("DropIndex(");
            writer.Write(Quote(dropIndexOperation.Table));
            writer.Write(", ");

            if (!dropIndexOperation.HasDefaultName)
            {
                writer.Write(Quote(dropIndexOperation.Name));
            }
            else
            {
                writer.Write("New String() { ");
                writer.Write(dropIndexOperation.Columns.Join(Quote));
                writer.Write(" }");
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code for the given annotation value, which may be null. The default behavior is to use an
        /// <see cref="AnnotationCodeGenerator"/> if one is registered, otherwise call ToString on the annotation value.
        /// </summary>
        /// <remarks>
        /// Note that a <see cref="AnnotationCodeGenerator"/> can be registered to generate code for custom annotations
        /// without the need to override the entire code generator.
        /// </remarks>
        /// <param name="name">The name of the annotation for which code is needed.</param>
        /// <param name="annotation">The annotation value to generate.</param>
        /// <param name="writer">The writer to which generated code should be written.</param>
        protected internal virtual void GenerateAnnotation(string name, object annotation, IndentedTextWriter writer)
        {
            Check.NotEmpty(name, "name");
            Check.NotNull(writer, "writer");

            if (annotation == null)
            {
                writer.Write("Nothing");
                return;
            }

            Func<AnnotationCodeGenerator> annotationGenerator;
            if (AnnotationGenerators.TryGetValue(name, out annotationGenerator)
                && annotationGenerator != null)
            {
                annotationGenerator().Generate(name, annotation, writer);
            }
            else
            {
                writer.Write(Quote(annotation.ToString()));
            }
        }
        protected virtual string Generate(
            string migrationId, string sourceModel, string targetModel, string @namespace, string className)
        {
            Check.NotEmpty(migrationId, "migrationId");
            Check.NotEmpty(targetModel, "targetModel");
            Check.NotEmpty(className, "className");

            using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            {
                using (var writer = new IndentedTextWriter(stringWriter))
                {
                    writer.WriteLine("' <auto-generated />");

                    WriteClassStart(@namespace, className, writer, "Implements IMigrationMetadata", designer: true);

                    writer.Write("Private ReadOnly Resources As New ResourceManager(GetType(");
                    writer.Write(className);
                    writer.WriteLine("))");
                    writer.WriteLine();

                    WriteProperty("Id", Quote(migrationId), writer);
                    writer.WriteLine();
                    WriteProperty(
                        "Source",
                        sourceModel == null
                            ? null
                            : "Resources.GetString(\"Source\")",
                        writer);
                    writer.WriteLine();
                    WriteProperty("Target", "Resources.GetString(\"Target\")", writer);

                    WriteClassEnd(@namespace, writer);
                }

                return stringWriter.ToString();
            }
        }
        private void Generate(ProcedureOperation procedureOperation, string methodName, IndentedTextWriter writer)
        {
            DebugCheck.NotNull(procedureOperation);
            DebugCheck.NotEmpty(methodName);
            DebugCheck.NotNull(writer);

            writer.Write(methodName);
            writer.WriteLine("(");
            writer.Indent++;
            writer.Write(Quote(procedureOperation.Name));
            writer.WriteLine(",");

            if (procedureOperation.Parameters.Any())
            {
                writer.WriteLine("Function(p) New With");
                writer.Indent++;
                writer.WriteLine("{");
                writer.Indent++;

                procedureOperation.Parameters.Each(
                    (p, i) =>
                    {
                        var scrubbedName = ScrubName(p.Name);

                        writer.Write(".");
                        writer.Write(scrubbedName);
                        writer.Write(" =");
                        Generate(p, writer, !string.Equals(p.Name, scrubbedName, StringComparison.Ordinal));

                        if (i < procedureOperation.Parameters.Count - 1)
                        {
                            writer.Write(",");
                        }

                        writer.WriteLine();
                    });

                writer.Indent--;
                writer.WriteLine("},");
                writer.Indent--;
            }

            writer.Write("body :=");

            if (!string.IsNullOrWhiteSpace(procedureOperation.BodySql))
            {
                writer.WriteLine();
                writer.Indent++;

                var indentString
                    = "\" & vbCrLf & _"
                      + writer.NewLine
                      + writer.CurrentIndentation()
                      + "\"";

                writer.WriteLine(
                    Generate(
                        procedureOperation
                            .BodySql
                            .Replace(Environment.NewLine, indentString)));

                writer.Indent--;
            }
            else
            {
                writer.WriteLine(" \"\"");
            }

            writer.Indent--;
            writer.WriteLine(")");
            writer.WriteLine();
        }
        /// <summary>
        /// Generates a property to return the source or target model in the code behind file.
        /// </summary>
        /// <param name="name"> Name of the property. </param>
        /// <param name="value"> Value to be returned. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void WriteProperty(string name, string value, IndentedTextWriter writer)
        {
            Check.NotEmpty(name, "name");
            Check.NotNull(writer, "writer");

            writer.Write("Private ReadOnly Property IMigrationMetadata_");
            writer.Write(name);
            writer.Write("() As String Implements IMigrationMetadata.");
            writer.WriteLine(name);
            writer.Indent++;
            writer.WriteLine("Get");
            writer.Indent++;
            writer.Write("Return ");
            writer.WriteLine(value ?? "Nothing");
            writer.Indent--;
            writer.WriteLine("End Get");
            writer.Indent--;
            writer.WriteLine("End Property");
        }
        /// <summary>Generates code to perform a <see cref="T:System.Data.Entity.Migrations.Model.DropProcedureOperation" />.</summary>
        /// <param name="dropProcedureOperation">The operation to generate code for.</param>
        /// <param name="writer">Text writer to add the generated code to.</param>
        protected virtual void Generate(DropProcedureOperation dropProcedureOperation, IndentedTextWriter writer)
        {
            Check.NotNull(dropProcedureOperation, "dropProcedureOperation");
            Check.NotNull(writer, "writer");

            writer.Write("DropStoredProcedure(");
            writer.Write(Quote(dropProcedureOperation.Name));
            writer.WriteLine(")");
        }
        protected virtual void WriteClassStart(
            string @namespace, string className, IndentedTextWriter writer, string @base, bool designer = false,
            IEnumerable<string> namespaces = null)
        {
            Check.NotNull(writer, "writer");
            Check.NotEmpty(className, "className");
            Check.NotEmpty(@base, "base");

            (namespaces ?? GetDefaultNamespaces(designer)).Each(n => writer.WriteLine("Imports " + n));

            if (!designer)
            {
                writer.WriteLine("Imports Microsoft.VisualBasic");
            }

            writer.WriteLine();

            if (!string.IsNullOrWhiteSpace(@namespace))
            {
                writer.Write("Namespace ");
                writer.WriteLine(@namespace);
                writer.Indent++;
            }

            WriteClassAttributes(writer, designer);

            writer.Write("Public ");

            if (designer)
            {
                writer.Write("NotInheritable ");
            }

            writer.Write("Partial Class ");
            writer.Write(className);

            writer.WriteLine();
            writer.Indent++;
            writer.WriteLine(@base);
            writer.Indent--;

            writer.WriteLine();
            writer.Indent++;
        }
        /// <summary>
        /// Generates code for an <see cref="AlterTableOperation"/>.
        /// </summary>
        /// <param name="alterTableOperation">The operation for which code should be generated.</param>
        /// <param name="writer">The writer to which generated code should be written.</param>
        protected internal virtual void Generate(AlterTableOperation alterTableOperation, IndentedTextWriter writer)
        {
            Check.NotNull(alterTableOperation, "alterTableOperation");
            Check.NotNull(writer, "writer");

            writer.WriteLine("AlterTableAnnotations(");
            writer.Indent++;
            writer.Write(Quote(alterTableOperation.Name));
            writer.WriteLine(",");
            writer.WriteLine("Function(c) New With");
            writer.Indent++;
            writer.WriteLine("{");
            writer.Indent++;

            var columnCount = alterTableOperation.Columns.Count();

            alterTableOperation.Columns.Each(
                (c, i) =>
                {
                    var scrubbedName = ScrubName(c.Name);

                    writer.Write(".");
                    writer.Write(scrubbedName);
                    writer.Write(" =");
                    Generate(c, writer, !string.Equals(c.Name, scrubbedName, StringComparison.Ordinal));

                    if (i < columnCount - 1)
                    {
                        writer.Write(",");
                    }

                    writer.WriteLine();
                });

            writer.Indent--;
            writer.Write("}");
            writer.Indent--;

            if (alterTableOperation.Annotations.Any())
            {
                writer.WriteLine(",");
                writer.Write("annotations := ");
                GenerateAnnotations(alterTableOperation.Annotations, writer);
            }

            writer.Write(")");

            writer.WriteLine();
            writer.Indent--;
            writer.WriteLine();
        }
        /// <summary>
        /// Generates code to perform a <see cref="DropColumnOperation" />.
        /// </summary>
        /// <param name="dropColumnOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(DropColumnOperation dropColumnOperation, IndentedTextWriter writer)
        {
            Check.NotNull(dropColumnOperation, "dropColumnOperation");
            Check.NotNull(writer, "writer");

            writer.Write("DropColumn(");
            writer.Write(Quote(dropColumnOperation.Table));
            writer.Write(", ");
            writer.Write(Quote(dropColumnOperation.Name));

            if (dropColumnOperation.RemovedAnnotations.Any())
            {
                writer.Indent++;

                writer.WriteLine(",");
                writer.Write("removedAnnotations := ");
                GenerateAnnotations(dropColumnOperation.RemovedAnnotations, writer);

                writer.Indent--;
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform an <see cref="AddForeignKeyOperation" /> as part of a <see cref="CreateTableOperation" />.
        /// </summary>
        /// <param name="addForeignKeyOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void GenerateInline(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
        {
            Check.NotNull(addForeignKeyOperation, "addForeignKeyOperation");
            Check.NotNull(writer, "writer");

            writer.WriteLine(" _");
            writer.Write(".ForeignKey(" + Quote(addForeignKeyOperation.PrincipalTable) + ", ");
            Generate(addForeignKeyOperation.DependentColumns, writer);

            if (addForeignKeyOperation.CascadeDelete)
            {
                writer.Write(", cascadeDelete := True");
            }

            writer.Write(")");
        }
        /// <summary>
        /// Generates code to perform an <see cref="AlterColumnOperation" />.
        /// </summary>
        /// <param name="alterColumnOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(AlterColumnOperation alterColumnOperation, IndentedTextWriter writer)
        {
            Check.NotNull(alterColumnOperation, "alterColumnOperation");
            Check.NotNull(writer, "writer");

            writer.Write("AlterColumn(");
            writer.Write(Quote(alterColumnOperation.Table));
            writer.Write(", ");
            writer.Write(Quote(alterColumnOperation.Column.Name));
            writer.Write(", Function(c)");
            Generate(alterColumnOperation.Column, writer);
            writer.WriteLine(")");
        }
        protected virtual string Generate(
            IEnumerable<MigrationOperation> operations, string @namespace, string className)
        {
            Check.NotNull(operations, "operations");
            Check.NotEmpty(className, "className");

            using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            {
                using (var writer = new IndentedTextWriter(stringWriter))
                {
                    WriteClassStart(
                        @namespace, className, writer, "Inherits DbMigration", designer: false,
                        namespaces: GetNamespaces(operations));

                    writer.WriteLine("Public Overrides Sub Up()");
                    writer.Indent++;

                    operations
                        .Except(_newTableForeignKeys.Select(t => t.Item2))
                        .Except(_newTableIndexes.Select(t => t.Item2))
                        .Each<dynamic>(o => Generate(o, writer));

                    writer.Indent--;
                    writer.WriteLine("End Sub");

                    writer.WriteLine();

                    writer.WriteLine("Public Overrides Sub Down()");
                    writer.Indent++;

                    operations
                        = operations
                            .Select(o => o.Inverse)
                            .Where(o => o != null)
                            .Reverse();

                    var hasUnsupportedOperations
                        = operations.Any(o => o is NotSupportedOperation);

                    operations
                        .Where(o => !(o is NotSupportedOperation))
                        .Each<dynamic>(o => Generate(o, writer));

                    if (hasUnsupportedOperations)
                    {
                        writer.Write("Throw New NotSupportedException(");
                        writer.Write(Generate(Strings.ScaffoldSprocInDownNotSupported));
                        writer.WriteLine(")");
                    }

                    writer.Indent--;
                    writer.WriteLine("End Sub");

                    WriteClassEnd(@namespace, writer);
                }

                return stringWriter.ToString();
            }
        }
        /// <summary>
        /// Generates code for to re-create the given dictionary of annotations for use when passing
        /// these annotations as a parameter of a <see cref="DbMigration"/>. call.
        /// </summary>
        /// <param name="annotations">The annotations to generate.</param>
        /// <param name="writer">The writer to which generated code should be written.</param>
        protected internal virtual void GenerateAnnotations(IDictionary<string, object> annotations, IndentedTextWriter writer)
        {
            Check.NotNull(annotations, "annotations");
            Check.NotNull(writer, "writer");

            writer.WriteLine("New Dictionary(Of String, Object)() From _");
            writer.WriteLine("{");
            writer.Indent++;

            var names = annotations.Keys.OrderBy(k => k).ToArray();
            for (var i = 0; i < names.Length; i++)
            {
                writer.Write("{ ");
                writer.Write(Quote(names[i]) + ", ");
                GenerateAnnotation(names[i], annotations[names[i]], writer);
                writer.WriteLine(i < names.Length - 1 ? " }," : " }");
            }

            writer.Indent--;
            writer.Write("}");
        }
        /// <summary>
        /// Generates code to perform an <see cref="AddForeignKeyOperation" />.
        /// </summary>
        /// <param name="addForeignKeyOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
        {
            Check.NotNull(addForeignKeyOperation, "addForeignKeyOperation");
            Check.NotNull(writer, "writer");

            writer.Write("AddForeignKey(");
            writer.Write(Quote(addForeignKeyOperation.DependentTable));
            writer.Write(", ");

            var compositeKey = addForeignKeyOperation.DependentColumns.Count() > 1;

            if (compositeKey)
            {
                writer.Write("New String() { ");
            }

            writer.Write(addForeignKeyOperation.DependentColumns.Join(Quote));

            if (compositeKey)
            {
                writer.Write(" }");
            }

            writer.Write(", ");
            writer.Write(Quote(addForeignKeyOperation.PrincipalTable));

            if (addForeignKeyOperation.PrincipalColumns.Any())
            {
                writer.Write(", ");

                if (compositeKey)
                {
                    writer.Write("New String() { ");
                }

                writer.Write(addForeignKeyOperation.PrincipalColumns.Join(Quote));

                if (compositeKey)
                {
                    writer.Write(" }");
                }
            }

            if (addForeignKeyOperation.CascadeDelete)
            {
                writer.Write(", cascadeDelete := True");
            }

            if (!addForeignKeyOperation.HasDefaultName)
            {
                writer.Write(", name := ");
                writer.Write(Quote(addForeignKeyOperation.Name));
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code for to re-create the given dictionary of annotations for use when passing
        /// these annotations as a parameter of a <see cref="DbMigration"/>. call.
        /// </summary>
        /// <param name="annotations">The annotations to generate.</param>
        /// <param name="writer">The writer to which generated code should be written.</param>
        protected internal virtual void GenerateAnnotations(IDictionary<string, AnnotationValues> annotations, IndentedTextWriter writer)
        {
            Check.NotNull(annotations, "annotations");
            Check.NotNull(writer, "writer");

            writer.WriteLine("New Dictionary(Of String, AnnotationValues)() From _");
            writer.WriteLine("{");
            writer.Indent++;

            if (annotations != null)
            {
                var names = annotations.Keys.OrderBy(k => k).ToArray();
                for (var i = 0; i < names.Length; i++)
                {
                    writer.WriteLine("{");
                    writer.Indent++;
                    writer.WriteLine(Quote(names[i]) + ",");
                    writer.Write("New AnnotationValues(oldValue := ");
                    GenerateAnnotation(names[i], annotations[names[i]].OldValue, writer);
                    writer.Write(", newValue := ");
                    GenerateAnnotation(names[i], annotations[names[i]].NewValue, writer);
                    writer.WriteLine(")");
                    writer.Indent--;
                    writer.WriteLine(i < names.Length - 1 ? " }," : " }");
                }
            }

            writer.Indent--;
            writer.Write("}");
        }
        /// <summary>
        /// Generates code to perform an <see cref="AddPrimaryKeyOperation" />.
        /// </summary>
        /// <param name="addPrimaryKeyOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(AddPrimaryKeyOperation addPrimaryKeyOperation, IndentedTextWriter writer)
        {
            Check.NotNull(addPrimaryKeyOperation, "addPrimaryKeyOperation");
            Check.NotNull(writer, "writer");

            writer.Write("AddPrimaryKey(");
            writer.Write(Quote(addPrimaryKeyOperation.Table));
            writer.Write(", ");

            var compositeIndex = addPrimaryKeyOperation.Columns.Count() > 1;

            if (compositeIndex)
            {
                writer.Write("New String() { ");
            }

            writer.Write(addPrimaryKeyOperation.Columns.Join(Quote));

            if (compositeIndex)
            {
                writer.Write(" }");
            }

            if (!addPrimaryKeyOperation.HasDefaultName)
            {
                writer.Write(", name := ");
                writer.Write(Quote(addPrimaryKeyOperation.Name));
            }

            if (!addPrimaryKeyOperation.IsClustered)
            {
                writer.Write(", clustered := False");
            }

            writer.WriteLine(")");
        }
        /// <summary>
        /// Generates code to perform a <see cref="CreateIndexOperation" />.
        /// </summary>
        /// <param name="createIndexOperation"> The operation to generate code for. </param>
        /// <param name="writer"> Text writer to add the generated code to. </param>
        protected virtual void Generate(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
        {
            Check.NotNull(createIndexOperation, "createIndexOperation");
            Check.NotNull(writer, "writer");

            writer.Write("CreateIndex(");
            writer.Write(Quote(createIndexOperation.Table));
            writer.Write(", ");

            var compositeIndex = createIndexOperation.Columns.Count() > 1;

            if (compositeIndex)
            {
                writer.Write("New String() { ");
            }

            writer.Write(createIndexOperation.Columns.Join(Quote));

            if (compositeIndex)
            {
                writer.Write(" }");
            }

            WriteIndexParameters(createIndexOperation, writer);

            writer.WriteLine(")");
        }