运行 EF Code First 使用 Azure Managed Identity 迁移时如何修复 'CREATE SCHEMA' 失败错误

How to fix 'CREATE SCHEMA' failed error when running EF Code First migrations with Azure Managed Identity

我正在尝试 运行 EF6 Code First 针对通过 Azure Managed Identity 连接的 Azure SQL 数据库进行迁移。有几个迁移到 运行。最后一次迁移失败。此迁移与其他迁移不同,因为它在新架构中创建表。

这是在 运行 执行创建新模式的 Entity Framework Code First 迁移时返回的错误:

System.Data.SqlClient.SqlException: The specified schema name "uuid@uuid" either does not exist or you do not have permission to use it.
CREATE SCHEMA failed due to previous errors.

我已经在数据库上记录了 SQL 命令,似乎失败的命令是

IF schema_id('MyNewSchema') IS NULL
EXECUTE('CREATE SCHEMA [MyNewSchema]')

出现错误:

<batch_information><failure_reason>Err 2759, Level 16, Server mysqldbname
CREATE SCHEMA failed due to previous errors.</failure_reason></batch_information>

以下是系统的一些详细信息:

我尝试过的事情

1.添加角色

我尝试过的主要事情是使用 Microsoft 权限文档来确定需要什么权限。到目前为止,我已将以下角色添加到 App Service 运行ning 迁移连接为的包含用户:

db_ddladmin
db_datareader
db_datawriter
db_securityadmin
db_owner
db_accessadmin

(请注意,其他迁移仅使用 db_ddladmin、db_datareader 和 db_datawriter 即可正常工作)

2。 运行 作为服务器管理员迁移

我已经尝试 运行 以 SQL 服务器管理员用户身份进行迁移。这可行,但我们不允许以生产系统的 SQL 服务器管理员用户身份连接。

我刚刚 运行 使用 asp.net 核心 2.2 和 EF 核心遇到了同样的问题。我试图使用托管标识来创建架构并遇到相同的错误。我发现这篇文章表明它是一个错误 - https://techcommunity.microsoft.com/t5/Azure-Database-Support-Blog/Lesson-Learned-54-The-specified-schema-name-name-domain-com/ba-p/369152

我唯一的解决方法是使用服务器管理员创建架构,这并不理想。

如果您将 AUTHORIZATION 添加到 CREATE SCHEMA 命令,它会起作用。

所以语句 Entity Framework 创建需要看起来像这样:

IF schema_id('MyNewSchema') IS NULL
EXECUTE('CREATE SCHEMA [MyNewSchema] AUTHORIZATION [dbo]')

您可以通过覆盖 ApplicationSqlServerMigrationsSqlGenerator

来做到这一点
    protected override void Generate(EnsureSchemaOperation operation, IModel model, MigrationCommandListBuilder builder)
    {
        if (operation is null)
            throw new ArgumentNullException(nameof(operation));
        if (builder is null)
            throw new ArgumentNullException(nameof(builder));
        if (string.Equals(operation.Name, "dbo", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }
        var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
        builder
            .Append("IF SCHEMA_ID(")
            .Append(stringTypeMapping.GenerateSqlLiteral(operation.Name))
            .Append(") IS NULL EXEC(")
            .Append(
                stringTypeMapping.GenerateSqlLiteral(
                    "CREATE SCHEMA "
                    + Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name)
                    + " AUTHORIZATION "
                    + Dependencies.SqlGenerationHelper.DelimitIdentifier("dbo")
                    + Dependencies.SqlGenerationHelper.StatementTerminator))
            .Append(")")
            .AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator)
            .EndCommand();
    }

然后注册:

        services.AddDbContextPool<ApplicationDbContext>(options =>
        {
            options.UseSqlServer("Your connection string");
            options.ReplaceService<IMigrationsSqlGenerator, ApplicationSqlServerMigrationsSqlGenerator>();
        });

(上面的代码是针对 EF Core 的,因为我在那里遇到了问题)