public void Append_line_at_start_with_indent()
        {
            var indentedStringBuilder = new IndentedStringBuilder();

            using (indentedStringBuilder.Indent())
            {
                indentedStringBuilder.AppendLine("Foo");
            }

            Assert.Equal("    Foo\r\n", indentedStringBuilder.ToString());
        }
        public virtual IEnumerable<SqlStatement> Generate([NotNull] IEnumerable<MigrationOperation> migrationOperations)
        {
            Check.NotNull(migrationOperations, "migrationOperations");

            foreach (var operation in migrationOperations)
            {
                var builder = new IndentedStringBuilder();
                operation.GenerateSql(this, builder);
                yield return new SqlStatement(builder.ToString());
            }
        }
        public void Append_line_in_middle_when_no_new_line()
        {
            var indentedStringBuilder = new IndentedStringBuilder();

            indentedStringBuilder.AppendLine("Foo");

            using (indentedStringBuilder.Indent())
            {
                indentedStringBuilder.AppendLine("Foo");
            }

            Assert.Equal("Foo\r\n    Foo\r\n", indentedStringBuilder.ToString());
        }
        public void Generate_empty_model()
        {
            var builder = new ModelBuilder();

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

return builder.Model;",
                stringBuilder.ToString());
        }
        public override string Generate(
            string migrationNamespace,
            string migrationName,
            IReadOnlyList<MigrationOperation> upOperations,
            IReadOnlyList<MigrationOperation> downOperations)
        {
            Check.NotEmpty(migrationNamespace, nameof(migrationNamespace));
            Check.NotEmpty(migrationName, nameof(migrationName));
            Check.NotNull(upOperations, nameof(upOperations));
            Check.NotNull(downOperations, nameof(downOperations));

            var builder = new IndentedStringBuilder();
            builder
                .AppendLine("using System.Collections.Generic;")
                .AppendLine("using Microsoft.Data.Entity.Relational.Migrations;")
                .AppendLine("using Microsoft.Data.Entity.Relational.Migrations.Builders;")
                .AppendLine("using Microsoft.Data.Entity.Relational.Migrations.Operations;")
                .AppendLine()
                .Append("namespace ").AppendLine(migrationNamespace)
                .AppendLine("{");
            using (builder.Indent())
            {
                builder
                    .Append("public partial class ").Append(_code.Identifier(migrationName)).AppendLine(" : Migration")
                    .AppendLine("{");
                using (builder.Indent())
                {
                    builder
                        .AppendLine("public override void Up(MigrationBuilder migration)")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        _operationGenerator.Generate("migration", upOperations, builder);
                    }
                    builder
                        .AppendLine("}")
                        .AppendLine()
                        .AppendLine("public override void Down(MigrationBuilder migration)")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        _operationGenerator.Generate("migration", downOperations, builder);
                    }
                    builder.AppendLine("}");
                }
                builder.AppendLine("}");
            }
            builder.AppendLine("}");

            return builder.ToString();
        }
        public void Generate_empty_model_with_annotations()
        {
            var builder = new ModelBuilder()
                .Annotation("A1", "V1")
                .Annotation("A2", "V2");

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder()
    .Annotation(""A1"", ""V1"")
    .Annotation(""A2"", ""V2"");

return builder.Model;",
                stringBuilder.ToString());
        }
        public void Generate_entity_type_with_single_property()
        {
            var builder = new ModelBuilder();
            builder.Entity<Customer>(b =>
                {
                    b.Property(e => e.Id);
                    b.Key(e => e.Id);
                });

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

builder.Entity(""Customer"", b =>
    {
        b.Property<int>(""Id"");
        b.Key(""Id"");
    });

return builder.Model;",
                stringBuilder.ToString());
        }
        public virtual async Task<List<string>> GenerateAsync(
            [NotNull] ReverseEngineeringConfiguration configuration,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Check.NotNull(configuration, nameof(configuration));

            CheckConfiguration(configuration);

            var resultingFiles = new List<string>();
            var providerAssembly = configuration.ProviderAssembly;
            var provider = GetProvider(providerAssembly);
            var metadataModel = GetMetadataModel(provider, configuration);

            var dbContextGeneratorModel = new DbContextGeneratorModel
            {
                ClassName = configuration.ContextClassName,
                Namespace = configuration.Namespace,
                ProviderAssembly = configuration.ProviderAssembly.FullName,
                ConnectionString = configuration.ConnectionString,
                MetadataModel = metadataModel
            };

            //TODO - check to see whether user has an override class for this in the current project first
            var dbContextCodeGenerator =
                provider.GetContextModelCodeGenerator(this, dbContextGeneratorModel);
            if (dbContextCodeGenerator == null)
            {
                throw new InvalidOperationException(
                    Strings.NoContextModelCodeGenerator(provider.GetType().FullName));
            }

            CheckOutputFiles(configuration.OutputPath, dbContextCodeGenerator.ClassName, metadataModel);

            var contextStringBuilder = new IndentedStringBuilder();
            dbContextCodeGenerator.Generate(contextStringBuilder);

            // output DbContext .cs file
            var dbContextFileName = dbContextCodeGenerator.ClassName + FileExtension;
            using (var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(contextStringBuilder.ToString())))
            {
                await OutputFile(configuration.OutputPath, dbContextFileName, sourceStream);
            }
            resultingFiles.Add(Path.Combine(configuration.OutputPath, dbContextFileName));

            foreach (var entityType in metadataModel.EntityTypes)
            {
                var entityTypeGeneratorModel = new EntityTypeGeneratorModel()
                {
                    EntityType = entityType,
                    Namespace = configuration.Namespace,
                    ProviderAssembly = configuration.ProviderAssembly.FullName,
                    ConnectionString = configuration.ConnectionString,
                };

                //TODO - check to see whether user has an override class for this in the current project first
                var entityTypeCodeGenerator =
                    provider.GetEntityTypeModelCodeGenerator(
                        this,
                        entityTypeGeneratorModel);
                if (entityTypeCodeGenerator == null)
                {
                    throw new InvalidOperationException(
                        Strings.NoEntityTypeModelCodeGenerator(provider.GetType().FullName));
                }

                var entityTypeStringBuilder = new IndentedStringBuilder();
                entityTypeCodeGenerator.Generate(entityTypeStringBuilder);

                // output EntityType poco .cs file
                using (var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(entityTypeStringBuilder.ToString())))
                {
                    var entityTypeFileName = entityType.Name + FileExtension;
                    await OutputFile(configuration.OutputPath, entityTypeFileName, sourceStream);
                    resultingFiles.Add(Path.Combine(configuration.OutputPath, entityTypeFileName));
                }
            }

            return resultingFiles;
        }
        public void Generate_model_snapshot_class()
        {
            var model = new Model();
            var entityType = new EntityType("Entity");

            entityType.SetKey(entityType.AddProperty("Id", typeof(int)));
            model.AddEntityType(entityType);

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().GenerateModelSnapshotClass("MyNamespace", "MyClass", model, stringBuilder);

            Assert.Equal(
                @"using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;

namespace MyNamespace
{
    public class MyClass : ModelSnapshot
    {
        public override IModel Model
        {
            get
            {
                var builder = new ModelBuilder();
                
                builder.Entity(""Entity"", b =>
                    {
                        b.Property<int>(""Id"");
                        b.Key(""Id"");
                    });
                
                return builder.Model;
            }
        }
    }
}",
                stringBuilder.ToString());
        }
        private void Test(Action<ModelBuilder> buildModel, string expectedCode, Action<IModel> assert)
        {
            var modelBuilder = new ModelBuilderFactory().CreateConventionBuilder();
            buildModel(modelBuilder);
            var model = modelBuilder.Model;

            var generator = new CSharpModelGenerator(new CSharpHelper());

            var builder = new IndentedStringBuilder();
            generator.Generate(model, builder);
            var code = builder.ToString();

            Assert.Equal(expectedCode, code);

            var build = new BuildSource
            {
                References =
                {
                    BuildReference.ByName("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
                    BuildReference.ByName("System.Linq.Expressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
                    BuildReference.ByName("System.Runtime, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
                    BuildReference.ByName("EntityFramework.Core"),
                    BuildReference.ByName("EntityFramework.Relational"),
                },
                Sources = { @"
                    using System;
                    using Microsoft.Data.Entity;
                    using Microsoft.Data.Entity.Metadata;
                    using Microsoft.Data.Entity.Metadata.ModelConventions;
                    using Microsoft.Data.Entity.Relational.Migrations.Infrastructure;

                    
                    public static class ModelSnapshot
                    {
                        public static IModel Model
                        {
                            get
                            {
                                var builder = new ModelBuilder(new ConventionSet());
                                " + code + @"

                                return builder.Model;
                            }
                        }
                   }
                " }
            };

            var assembly = build.BuildInMemory();
            var factoryType = assembly.GetType("ModelSnapshot");
            var property = factoryType.GetProperty("Model");
            var value = (IModel)property.GetValue(null);

            Assert.NotNull(value);
            assert(value);
        }
Example #11
0
        public virtual string ScriptMigrations(
            string fromMigrationName,
            string toMigrationName,
            bool idempotent = false)
        {
            var migrations = _migrationAssembly.Migrations;

            if (string.IsNullOrEmpty(fromMigrationName))
            {
                fromMigrationName = InitialDatabase;
            }
            else if (fromMigrationName != InitialDatabase)
            {
                fromMigrationName = _idGenerator.ResolveId(fromMigrationName, migrations);
            }

            if (string.IsNullOrEmpty(toMigrationName))
            {
                toMigrationName = migrations.Last().Id;
            }
            else if (toMigrationName != InitialDatabase)
            {
                toMigrationName = _idGenerator.ResolveId(toMigrationName, migrations);
            }

            var builder = new IndentedStringBuilder();

            // If going up...
            if (string.Compare(fromMigrationName, toMigrationName, StringComparison.OrdinalIgnoreCase) <= 0)
            {
                var migrationsToApply = migrations.Where(
                    m => string.Compare(m.Id, fromMigrationName, StringComparison.OrdinalIgnoreCase) > 0
                         && string.Compare(m.Id, toMigrationName, StringComparison.OrdinalIgnoreCase) <= 0);
                var checkFirst = true;
                foreach (var migration in migrationsToApply)
                {
                    if (checkFirst)
                    {
                        if (migration == migrations[0])
                        {
                            builder.AppendLine(_historyRepository.Create(ifNotExists: true));
                            builder.AppendLine(_sqlGenerator.BatchSeparator);
                            builder.AppendLine();
                        }

                        checkFirst = false;
                    }

                    _logger.Value.LogVerbose(Strings.GeneratingUp(migration.Id));

                    foreach (var batch in ApplyMigration(migration))
                    {
                        if (idempotent)
                        {
                            builder.AppendLine(_historyRepository.BeginIfNotExists(migration.Id));
                            using (builder.Indent())
                            {
                                var lines = batch.Sql.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                                foreach (var line in lines)
                                {
                                    builder.AppendLine(line);
                                }
                            }
                            builder.AppendLine(_historyRepository.EndIf());
                        }
                        else
                        {
                            builder.Append(batch.Sql);
                        }

                        builder.AppendLine(_sqlGenerator.BatchSeparator);
                        builder.AppendLine();
                    }
                }
            }
            else // If going down...
            {
                var migrationsToRevert = migrations
                    .Where(
                        m => string.Compare(m.Id, toMigrationName, StringComparison.OrdinalIgnoreCase) > 0
                             && string.Compare(m.Id, fromMigrationName, StringComparison.OrdinalIgnoreCase) <= 0)
                    .OrderByDescending(m => m.Id);
                foreach (var migration in migrationsToRevert)
                {
                    _logger.Value.LogVerbose(Strings.GeneratingDown(migration.Id));

                    foreach (var batch in RevertMigration(migration))
                    {
                        if (idempotent)
                        {
                            builder.AppendLine(_historyRepository.BeginIfExists(migration.Id));
                            using (builder.Indent())
                            {
                                var lines = batch.Sql.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                                foreach (var line in lines)
                                {
                                    builder.AppendLine(line);
                                }
                            }
                            builder.AppendLine(_historyRepository.EndIf());
                        }
                        else
                        {
                            builder.Append(batch.Sql);
                        }

                        builder.AppendLine(_sqlGenerator.BatchSeparator);
                        builder.AppendLine();
                    }
                }
            }

            return builder.ToString();
        }
        public void Generate_entity_type_with_composite_key()
        {
            var builder = new ModelBuilder();
            builder.Entity<Customer>(b =>
                {
                    b.Property(e => e.Id);
                    b.Property(e => e.Name);
                    b.Key(e => new { e.Id, e.Name })
                        .Annotation("A1", "V1")
                        .Annotation("A2", "V2");
                });

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

builder.Entity(""Customer"", b =>
    {
        b.Property<int>(""Id"");
        b.Property<string>(""Name"");
        b.Key(k => k.Properties(""Id"", ""Name"")
            .Annotation(""A1"", ""V1"")
            .Annotation(""A2"", ""V2""));
    });

return builder.Model;",
                stringBuilder.ToString());
        }
        public void Generate_entity_type_with_shadow_property_and_concurrency_token()
        {
            var builder = new ModelBuilder();
            builder.Entity<Customer>(b =>
                {
                    b.Property<int>("Id", shadowProperty: true, concurrencyToken: true);
                    b.Key(e => e.Id);
                });

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

builder.Entity(""Customer"", b =>
    {
        b.Property<int>(""Id"", shadowProperty: true, concurrencyToken: true);
        b.Key(""Id"");
    });

return builder.Model;",
                stringBuilder.ToString());
        }
        public void Generate_migration_metadata_class()
        {
            var model = new Model();
            var entityType = new EntityType("Entity");

            entityType.SetKey(entityType.AddProperty("Id", typeof(int)));
            model.AddEntityType(entityType);

            var migration
                = new MigrationMetadata("000000000000001_Name")
                    {
                        TargetModel = model
                    };

            var codeGenerator = new CSharpMigrationCodeGenerator(new CSharpModelCodeGenerator());
            var stringBuilder = new IndentedStringBuilder();

            codeGenerator.GenerateMigrationMetadataClass("MyNamespace", "MyClass", migration, stringBuilder);

            Assert.Equal(
                @"using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;

namespace MyNamespace
{
    public partial class MyClass : IMigrationMetadata
    {
        string IMigrationMetadata.MigrationId
        {
            get
            {
                return ""000000000000001_Name"";
            }
        }
        
        IModel IMigrationMetadata.TargetModel
        {
            get
            {
                var builder = new ModelBuilder();
                
                builder.Entity(""Entity"", b =>
                    {
                        b.Property<int>(""Id"");
                        b.Key(""Id"");
                    });
                
                return builder.Model;
            }
        }
    }
}",
                stringBuilder.ToString());
        }
        public void Generate_migration_class()
        {
            var upgradeOperations
                = new[]
                    {
                        new AddColumnOperation("dbo.MyTable", new Column("Foo", typeof(int))),
                        new AddColumnOperation("dbo.MyTable", new Column("Bar", typeof(int)))
                    };

            var downgradeOperations
                = new[]
                    {
                        new DropColumnOperation("dbo.MyTable", "Foo"),
                        new DropColumnOperation("dbo.MyTable", "Bar")
                    };

            var migration
                = new MigrationMetadata("000000000000001_Name")
                    {
                        UpgradeOperations = upgradeOperations,
                        DowngradeOperations = downgradeOperations
                    };

            var codeGenerator = new CSharpMigrationCodeGenerator(new CSharpModelCodeGenerator());
            var stringBuilder = new IndentedStringBuilder();

            codeGenerator.GenerateMigrationClass("MyNamespace", "MyClass", migration, stringBuilder);

            Assert.Equal(
                @"using Microsoft.Data.Entity.Migrations;
using Microsoft.Data.Entity.Migrations.Builders;
using System;

namespace MyNamespace
{
    public partial class MyClass : Migration
    {
        public override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.AddColumn(""dbo.MyTable"", ""Foo"", c => c.Int());
            
            migrationBuilder.AddColumn(""dbo.MyTable"", ""Bar"", c => c.Int());
        }
        
        public override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropColumn(""dbo.MyTable"", ""Foo"");
            
            migrationBuilder.DropColumn(""dbo.MyTable"", ""Bar"");
        }
    }
}",
                stringBuilder.ToString());
        }
        public virtual void GenerateOnModelCreatingCode([NotNull] IndentedStringBuilder sb)
        {
            Check.NotNull(sb, nameof(sb));

            Generator.CSharpCodeGeneratorHelper.BeginMethod(AccessModifier.Protected,
                VirtualModifier.Override, "void", "OnModelCreating", sb, _onModelCreatingMethodParameters);

            var first = true;
            foreach (var entityType in OrderedEntityTypes())
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    sb.AppendLine();
                }
                sb.Append("modelBuilder.Entity<");
                sb.Append(entityType.Name);
                sb.AppendLine(">(entity =>");
                GenerateEntityKeyAndPropertyConfiguration(entityType, sb);
                sb.AppendLine(");");
            }

            foreach (var entityType in OrderedEntityTypes())
            {
                var navigationsStringBuilder = new IndentedStringBuilder(sb);
                navigationsStringBuilder.IncrementIndent();
                GenerateNavigationsConfiguration(entityType, navigationsStringBuilder);
                var navigationsCode = navigationsStringBuilder.ToString();
                if (!string.IsNullOrEmpty(navigationsCode))
                {
                    sb.AppendLine();
                    sb.Append("modelBuilder.Entity<");
                    sb.Append(entityType.Name);
                    sb.AppendLine(">(entity =>");
                    sb.AppendLine("{");
                    sb.DecrementIndent().DecrementIndent().DecrementIndent();
                    sb.AppendLine(navigationsCode);
                    sb.IncrementIndent().IncrementIndent().IncrementIndent();
                    sb.AppendLine("});");
                }
            }

            Generator.CSharpCodeGeneratorHelper.EndMethod(sb);
        }
        public override string GenerateSnapshot(
            string modelSnapshotNamespace,
            Type contextType,
            string modelSnapshotName,
            IModel model)
        {
            Check.NotEmpty(modelSnapshotNamespace, nameof(modelSnapshotNamespace));
            Check.NotNull(contextType, nameof(contextType));
            Check.NotEmpty(modelSnapshotName, nameof(modelSnapshotName));
            Check.NotNull(model, nameof(model));

            var builder = new IndentedStringBuilder();
            builder
                .AppendLine("using System;")
                .AppendLine("using Microsoft.Data.Entity;")
                .AppendLine("using Microsoft.Data.Entity.Metadata;")
                .AppendLine("using Microsoft.Data.Entity.Relational.Migrations.Infrastructure;")
                .Append("using ").Append(contextType.Namespace).AppendLine(";")
                .AppendLine()
                .Append("namespace ").AppendLine(modelSnapshotNamespace)
                .AppendLine("{");
            using (builder.Indent())
            {
                builder
                    .Append("[ContextType(typeof(").Append(_code.Reference(contextType)).AppendLine("))]")
                    .Append("partial class ").Append(_code.Identifier(modelSnapshotName)).AppendLine(" : ModelSnapshot")
                    .AppendLine("{");
                using (builder.Indent())
                {
                    builder
                        .AppendLine("public override void BuildModel(ModelBuilder builder)")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        _modelGenerator.Generate(model, builder);
                    }
                    builder.AppendLine("}");
                }
                builder.AppendLine("}");
            }
            builder.AppendLine("}");

            return builder.ToString();
        }
        public void Generate_entity_type_with_single_composite_foreign_key()
        {
            var builder = new ModelBuilder();

            builder.Entity<Customer>(b =>
                {
                    b.Property(e => e.Id);
                    b.Property(e => e.Name);
                    b.Key(e => new { e.Id, e.Name });
                });

            builder.Entity<Order>(b =>
                {
                    b.Property(e => e.Id);
                    b.Property(e => e.CustomerId);
                    b.Property(e => e.CustomerName);
                    b.Key(e => e.Id);
                });

            builder.Entity<Order>()
                .ForeignKeys(fks => fks.ForeignKey<Customer>(e => new { e.CustomerId, e.CustomerName }));

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

builder.Entity(""Customer"", b =>
    {
        b.Property<int>(""Id"");
        b.Property<string>(""Name"");
        b.Key(""Id"", ""Name"");
    });

builder.Entity(""Order"", b =>
    {
        b.Property<int>(""CustomerId"");
        b.Property<string>(""CustomerName"");
        b.Property<int>(""Id"");
        b.Key(""Id"");
        b.ForeignKeys(fks => fks.ForeignKey(""Customer"", ""CustomerId"", ""CustomerName""));
    });

return builder.Model;",
                stringBuilder.ToString());
        }
        public override string GenerateMetadata(
            string migrationNamespace,
            Type contextType,
            string migrationName,
            string migrationId,
            string productVersion,
            IModel targetModel)
        {
            Check.NotEmpty(migrationNamespace, nameof(migrationNamespace));
            Check.NotNull(contextType, nameof(contextType));
            Check.NotEmpty(migrationName, nameof(migrationName));
            Check.NotEmpty(migrationId, nameof(migrationId));
            Check.NotEmpty(productVersion, nameof(productVersion));
            Check.NotNull(targetModel, nameof(targetModel));

            var builder = new IndentedStringBuilder();
            builder
                .AppendLine("using System;")
                .AppendLine("using Microsoft.Data.Entity;")
                .AppendLine("using Microsoft.Data.Entity.Metadata;")
                .AppendLine("using Microsoft.Data.Entity.Relational.Migrations.Infrastructure;")
                .Append("using ").Append(contextType.Namespace).AppendLine(";")
                .AppendLine()
                .Append("namespace ").AppendLine(migrationNamespace)
                .AppendLine("{");
            using (builder.Indent())
            {
                builder
                    .Append("[ContextType(typeof(").Append(_code.Reference(contextType)).AppendLine("))]")
                    .Append("partial class ").AppendLine(_code.Identifier(migrationName))
                    .AppendLine("{");
                using (builder.Indent())
                {
                    builder
                        .AppendLine("public override string Id")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        builder.Append("get { return ").Append(_code.Literal(migrationId)).AppendLine("; }");
                    }
                    builder
                        .AppendLine("}")
                        .AppendLine()
                        .AppendLine("public override string ProductVersion")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        builder.Append("get { return ").Append(_code.Literal(productVersion)).AppendLine("; }");
                    }
                    builder
                        .AppendLine("}")
                        .AppendLine()
                        .AppendLine("public override void BuildTargetModel(ModelBuilder builder)")
                        .AppendLine("{");
                    using (builder.Indent())
                    {
                        // TODO: Optimize. This is repeated below
                        _modelGenerator.Generate(targetModel, builder);
                    }
                    builder.AppendLine("}");
                }
                builder.AppendLine("}");
            }
            builder.AppendLine("}");

            return builder.ToString();
        }
        public void Generate_entity_type_with_multiple_foreign_keys_with_annotations()
        {
            var builder = new ModelBuilder();
            builder.Entity<Customer>(b =>
                {
                    b.Property(e => e.Id);
                    b.Property(e => e.Name);
                    b.Key(e => new { e.Id, e.Name });
                });

            builder.Entity<Order>(b =>
                {
                    b.Property(e => e.Id);
                    b.Property(e => e.CustomerId);
                    b.Property(e => e.CustomerName);
                    b.Property(e => e.ProductId);
                    b.Key(e => e.Id);
                });

            builder.Entity<Product>(b =>
                {
                    b.Property(e => e.Id);
                    b.Key(e => e.Id);
                });

            builder.Entity<Order>()
                .ForeignKeys(
                    fks =>
                        {
                            fks.ForeignKey<Customer>(e => new { e.CustomerId, e.CustomerName })
                                .Annotation("A1", "V1")
                                .Annotation("A2", "V2");
                            fks.ForeignKey<Product>(e => e.ProductId)
                                .Annotation("A3", "V3")
                                .Annotation("A4", "V4");
                        });

            var stringBuilder = new IndentedStringBuilder();
            new CSharpModelCodeGenerator().Generate(builder.Model, stringBuilder);

            Assert.Equal(
                @"var builder = new ModelBuilder();

builder.Entity(""Customer"", b =>
    {
        b.Property<int>(""Id"");
        b.Property<string>(""Name"");
        b.Key(""Id"", ""Name"");
    });

builder.Entity(""Order"", b =>
    {
        b.Property<int>(""CustomerId"");
        b.Property<string>(""CustomerName"");
        b.Property<int>(""Id"");
        b.Property<int>(""ProductId"");
        b.Key(""Id"");
        b.ForeignKeys(fks => 
            {
                fks.ForeignKey(""Customer"", ""CustomerId"", ""CustomerName"")
                    .Annotation(""A1"", ""V1"")
                    .Annotation(""A2"", ""V2"");
                fks.ForeignKey(""Product"", ""ProductId"")
                    .Annotation(""A3"", ""V3"")
                    .Annotation(""A4"", ""V4"");
            });
    });

builder.Entity(""Product"", b =>
    {
        b.Property<int>(""Id"");
        b.Key(""Id"");
    });

return builder.Model;",
                stringBuilder.ToString());
        }
        public virtual string Create(bool ifNotExists)
        {
            var builder = new IndentedStringBuilder();

            if (ifNotExists)
            {
                builder.AppendLine("IF NOT EXISTS(SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE[TABLE_SCHEMA] = N'dbo' AND[TABLE_NAME] = '" + MigrationHistoryTableName + "' AND[TABLE_TYPE] = 'BASE TABLE')");
                builder.IncrementIndent();
            }

            builder
                .AppendLine("CREATE TABLE [dbo].[" + MigrationHistoryTableName + "] (");
            using (builder.Indent())
            {
                builder
                    .AppendLine("[MigrationId] nvarchar(150) NOT NULL,")
                    .AppendLine("[ContextKey] nvarchar(300) NOT NULL,")
                    .AppendLine("[ProductVersion] nvarchar(32) NOT NULL,")
                    .AppendLine("CONSTRAINT [PK_MigrationHistory] PRIMARY KEY ([MigrationId], [ContextKey])");
            }
            builder.Append(");");

            return builder.ToString();
        }
        public virtual ScaffoldedMigration ScaffoldMigration([NotNull] string migrationName)
        {
            Check.NotEmpty(migrationName, "migrationName");

            if (MigrationAssembly.Migrations.Any(m => m.GetMigrationName() == migrationName))
            {
                throw new InvalidOperationException(Strings.FormatDuplicateMigrationName(migrationName));
            }

            var migration = CreateMigration(migrationName);

            var migrationCode = new IndentedStringBuilder();
            var migrationMetadataCode = new IndentedStringBuilder();
            var snapshotModelCode = new IndentedStringBuilder();

            ScaffoldMigration(migration, migrationCode, migrationMetadataCode);
            ScaffoldSnapshotModel(migration.TargetModel, snapshotModelCode);

            return
                new ScaffoldedMigration()
                    {
                        MigrationNamespace = MigrationNamespace,
                        MigrationClass = GetClassName(migration),
                        SnapshotModelClass = GetClassName(migration.TargetModel),
                        MigrationCode = migrationCode.ToString(),
                        MigrationMetadataCode = migrationMetadataCode.ToString(),
                        SnapshotModelCode = snapshotModelCode.ToString()
                    };
        }