自訂移轉作業

MigrationBuilder API 可讓您在移轉期間執行許多不同類型的作業,但遠非詳盡。 不過,API 也是可延伸的,可讓您定義自己的作業。 有兩種方式可以擴充 API:使用 Sql() 方法,或藉由定義自訂 MigrationOperation 物件。

為了說明,讓我們看看實作作業,以使用每個方法建立資料庫使用者。 在我們的移轉中,我們想要啟用撰寫下列程式碼:

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

使用 MigrationBuilder.Sql()

實作自訂作業最簡單的方式是定義呼叫 MigrationBuilder.Sql() 的擴充方法。 以下是產生適當 Transact-SQL 的範例。

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

提示

當語句必須是 SQL 批次中的第一個或只有一個時,請使用 函 EXEC 式。 可能也需要解決等冪移轉腳本中的剖析器錯誤,這些錯誤可能會在資料表上目前不存在參考的資料行時發生。

如果您的移轉需要支援多個資料庫提供者,您可以使用 MigrationBuilder.ActiveProvider 屬性。 以下是同時支援 Microsoft SQL Server 和 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.");
}

只有在您知道將套用自訂作業的每個提供者時,這個方法才有效。

使用 MigrationOperation

若要將自訂作業與 SQL 分離,您可以定義自己的 MigrationOperation 來表示它。 接著,作業會傳遞至提供者,以便判斷要產生的適當 SQL。

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

使用此方法時,擴充方法只需要將其中一項作業新增至 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);
}

這種方法需要每個提供者知道如何在其服務中產生這項作業的 IMigrationsSqlGenerator SQL。 以下是覆寫 SQL Server 產生器以處理新作業的範例。

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

以更新的移轉取代預設移轉 sql 產生器服務。

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