Operace vlastních migrací

Rozhraní API MigrationBuilder umožňuje provádět během migrace mnoho různých druhů operací, ale zdaleka není vyčerpávající. Rozhraní API je ale také rozšiřitelné a umožňuje definovat vlastní operace. Rozhraní API můžete rozšířit dvěma způsoby: pomocí Sql() metody nebo definováním vlastních MigrationOperation objektů.

Pojďme se podívat na implementaci operace, která vytvoří uživatele databáze pomocí jednotlivých přístupů. V našich migracích chceme povolit psaní následujícího kódu:

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

Použití MigrationBuilder.Sql()

Nejjednodušší způsob, jak implementovat vlastní operaci, je definovat rozšiřující metodu, která volá MigrationBuilder.Sql(). Tady je příklad, který vygeneruje odpovídající transact-SQL.

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

Tip

EXEC Funkci použijte, když příkaz musí být první nebo pouze jeden v dávce SQL. Může být také potřeba vyřešit chyby analyzátoru ve skriptech idempotentní migrace, ke kterým může dojít, když odkazované sloupce v tabulce aktuálně neexistují.

Pokud vaše migrace potřebuje podporovat více zprostředkovatelů databáze, můžete tuto vlastnost použít MigrationBuilder.ActiveProvider . Tady je příklad podpory Microsoft SQL Serveru i 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.");
}

Tento přístup funguje jenom v případě, že znáte každého poskytovatele, u kterého se použije vaše vlastní operace.

Použití migrationOperation

Pokud chcete oddělit vlastní operaci od SQL, můžete definovat vlastní MigrationOperation , která ji bude reprezentovat. Operace se pak předá poskytovateli, aby mohl určit odpovídající SQL, který se má vygenerovat.

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

S tímto přístupem stačí, aby metoda rozšíření přidala jednu z těchto operací do 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);
}

Tento přístup vyžaduje, aby každý poskytovatel věděl, jak vygenerovat SQL pro tuto operaci ve své službě IMigrationsSqlGenerator . Tady je příklad přepsání generátoru SQL Serveru pro zpracování nové operace.

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();
    }
}

Nahraďte výchozí službu generátoru SQL aktualizovanou službou.

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