Bagikan melalui


Operasi Migrasi Kustom

MigrationBuilder API memungkinkan Anda melakukan berbagai jenis operasi selama migrasi, tetapi jauh dari lengkap. Namun, API juga dapat diperluas memungkinkan Anda menentukan operasi Anda sendiri. Ada dua cara untuk memperluas API: Menggunakan Sql() metode , atau dengan menentukan objek kustom MigrationOperation .

Untuk mengilustrasikan, mari kita lihat menerapkan operasi yang membuat pengguna database menggunakan setiap pendekatan. Dalam migrasi kami, kami ingin mengaktifkan penulisan kode berikut:

migrationBuilder.CreateUser("SQLUser1", "Password");

Menggunakan MigrationBuilder.Sql()

Cara term mudah untuk mengimplementasikan operasi kustom adalah dengan menentukan metode ekstensi yang memanggil MigrationBuilder.Sql(). Berikut adalah contoh yang menghasilkan Transact-SQL yang sesuai.

public static OperationBuilder<SqlOperation> CreateUser(
    this MigrationBuilder migrationBuilder,
    string name,
    string password)
    => migrationBuilder.Sql($"CREATE USER {name} WITH PASSWORD '{password}';");

Tip

EXEC Gunakan fungsi saat pernyataan harus menjadi yang pertama atau hanya satu dalam batch SQL. Mungkin juga diperlukan untuk mengatasi kesalahan pengurai dalam skrip migrasi idempogen yang dapat terjadi ketika kolom yang dirujuk saat ini tidak ada di tabel.

Jika migrasi Anda perlu mendukung beberapa penyedia database, Anda dapat menggunakan properti .MigrationBuilder.ActiveProvider Berikut adalah contoh yang mendukung Microsoft SQL Server dan PostgreSQL.

public static OperationBuilder<SqlOperation> CreateUser(
    this MigrationBuilder migrationBuilder,
    string name,
    string password)
{
    switch (migrationBuilder.ActiveProvider)
    {
        case "Npgsql.EntityFrameworkCore.PostgreSQL":
            return migrationBuilder
                .Sql($"CREATE USER {name} WITH PASSWORD '{password}';");

        case "Microsoft.EntityFrameworkCore.SqlServer":
            return migrationBuilder
                .Sql($"CREATE USER {name} WITH PASSWORD = '{password}';");
    }

    throw new Exception("Unexpected provider.");
}

Pendekatan ini hanya berfungsi jika Anda mengetahui setiap penyedia tempat operasi kustom Anda akan diterapkan.

Menggunakan MigrationOperation

Untuk memisahkan operasi kustom dari SQL, Anda dapat menentukan sendiri MigrationOperation untuk mewakilinya. Operasi kemudian diteruskan ke penyedia sehingga dapat menentukan SQL yang sesuai untuk dihasilkan.

public class CreateUserOperation : MigrationOperation
{
    public string Name { get; set; }
    public string Password { get; set; }
}

Dengan pendekatan ini, metode ekstensi hanya perlu menambahkan salah satu operasi ini ke MigrationBuilder.Operations.

public static OperationBuilder<CreateUserOperation> CreateUser(
    this MigrationBuilder migrationBuilder,
    string name,
    string password)
{
    var operation = new CreateUserOperation { Name = name, Password = password };
    migrationBuilder.Operations.Add(operation);

    return new OperationBuilder<CreateUserOperation>(operation);
}

Pendekatan ini mengharuskan setiap penyedia untuk mengetahui cara menghasilkan SQL untuk operasi ini dalam layanan mereka IMigrationsSqlGenerator . Berikut adalah contoh mengesampingkan generator SQL Server untuk menangani operasi baru.

public class MyMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
{
    public MyMigrationsSqlGenerator(
        MigrationsSqlGeneratorDependencies dependencies,
        ICommandBatchPreparer commandBatchPreparer)
        : base(dependencies, commandBatchPreparer)
    {
    }

    protected override void Generate(
        MigrationOperation operation,
        IModel model,
        MigrationCommandListBuilder builder)
    {
        if (operation is CreateUserOperation createUserOperation)
        {
            Generate(createUserOperation, builder);
        }
        else
        {
            base.Generate(operation, model, builder);
        }
    }

    private void Generate(
        CreateUserOperation operation,
        MigrationCommandListBuilder builder)
    {
        var sqlHelper = Dependencies.SqlGenerationHelper;
        var stringMapping = Dependencies.TypeMappingSource.FindMapping(typeof(string));

        builder
            .Append("CREATE USER ")
            .Append(sqlHelper.DelimitIdentifier(operation.Name))
            .Append(" WITH PASSWORD = ")
            .Append(stringMapping.GenerateSqlLiteral(operation.Password))
            .AppendLine(sqlHelper.StatementTerminator)
            .EndCommand();
    }
}

Ganti layanan generator sql migrasi default dengan yang diperbarui.

protected override void OnConfiguring(DbContextOptionsBuilder options)
    => options
        .UseSqlServer(_connectionString)
        .ReplaceService<IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();