首页 > 解决方案 > 如何通过代码直接使用 EF Core Migrations API

问题描述

使用 Entity Framework Core,我们可以生成 C# 迁移文件,其中包含用于创建表、列、索引等的数据库信息……然后我们可以使用命令行或使用 EF DbContext 部署数据库。

有没有办法通过代码直接使用 Migrations API 来修改数据库,而不使用“真正的”迁移(没有代码模型或 dbContext)?

我想做这样的事情:

var builder = new MigrationBuilder(activeProvider);
builder.CreateTable(
    name: "Table1",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false),
        Name = table.Column<string>(maxLength: 256, nullable: true)
    });

Apply(builder, connectionString);

我应该Apply在我的数据库中创建表的方法中添加什么?

标签: c#entity-framework-coreentity-framework-migrations

解决方案


我进入了 EF Core 内部,并找到了一种使用 API 的方法。

我不确定这是否是一个好主意,或者它是否可以正常工作,但它适用于一个简单的案例(创建表,添加列)。

首先,我们需要注册一些 EF Core 服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<ICurrentDbContext, CurrentDbContext>();
    services.AddScoped<RelationalConnectionDependencies>();
    services.AddEntityFrameworkSqlServer();

    DbContextOptionsBuilder dbContextOptionsBuilder = new DbContextOptionsBuilder<DbContext>();
    dbContextOptionsBuilder.UseSqlServer("Data Source=.\\SQLEXPRESS;Initial Catalog=TestDeploy;Integrated Security=True;");
    services.AddSingleton<IDbContextOptions>(dbContextOptionsBuilder.Options);
    services.AddDbContext<DbContext>();

    services.AddScoped<MyMigrationRunner>();
}

我们不直接使用DbContext,但似乎是在内部使用。我们不需要任何特定的东西,我们可以从 EF Core 注册基本 DbContext。

另外,我使用了 SqlServer 特定的实现,我认为它可以与其他提供程序一起使用,但我没有测试。

为了构建数据库,我创建了一个迁移类

public class MyMigration : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Table1",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false),
                Name = table.Column<string>(maxLength: 256, nullable: true)
            });
    }
}

现在我可以使用该IMigrationsSqlGenerator服务生成 SQL 命令并将它们应用到数据库

public class MyMigrationRunner
{
    private readonly IRelationalConnection connection;
    private readonly IMigrationsSqlGenerator migrationsSqlGenerator;

    public MyMigrationRunner(IMigrationsSqlGenerator migrationsSqlGenerator, IRelationalConnection connection)
    {
        this.migrationsSqlGenerator = migrationsSqlGenerator;
        this.connection = connection;
    }

    public void Run()
    {
        var migration = new MyMigration();
        var commands = migrationsSqlGenerator.Generate(migration.UpOperations).ToList();
        foreach (var cmd in commands)
        {
            cmd.ExecuteNonQuery(connection);
        }
    }
}

推荐阅读