EF Core和运行时定义的模式

时间:2019-12-03 14:12:26

标签: c# entity-framework .net-core ef-core-2.2

免责声明

我试图寻找答案,但是我发现的解决方案对我不起作用。

情况

我有一个EF Core 2.2项目,其配置文件中定义了一个架构。

例如,每个用户应具有自己的环境,包括数据表,迁移表等。因此,存在一个配置文件(不一定受版本控制),该文件定义了架构名称。

失败

创建迁移时,EFCore工具将架构名称(无论运行时是什么)硬连接到快照和迁移代码。

我设法在任意模式下创建迁移表。

services
   .AddDbContext<AppDbContext>(opt =>
       opt.UseSqlServer(
           cred.Database.ConnectionString,
           opt => opt.MigrationsHistoryTable(
               "__EFMigrationsHistory", cred.Database.Schema)));

但是数据表仍然是在运行“添加迁移”工具时定义的架构中创建的。

尝试了什么

modelBuilder.HasDefaultSchema(mSchema.Schema)

似乎没有效果。

modelBuilder.Entity<>.ToTable(nameof(...), mSchema.Schema)

这(与前面的代码一起)使查询在新模式中查找表。 我不需要玩IModelCacheKey,因为一次只有一个模型,所以我没有。

Remove schema parameters from migration CS file

我认为这将迫使EF Core使用上面指定的默认架构。而是以dbo模式创建数据表。

更新

看起来,EFCore的核心使用多个架构没有问题。这是“添加迁移”工具,可使用硬编码模式生成迁移。无论出于何种原因,Ans迁移和模型定义都是完全分开的。

有人可以指出我正确的方向吗?

1 个答案:

答案 0 :(得分:0)

万一有人想知道-我找到了解决方案。它涉及到向EF迁移管道中注入一些代码,就像这样。

Startup.ConfigureServices中:

services
    .AddEntityFrameworkSqlServer()
    .AddScoped<IMigrationsSqlGenerator, SchemaMigrationsSqlGenerator>()
    .AddScoped<MigrationsSqlGenerator, SqlServerMigrationsSqlGenerator>()
    .AddDbContext<AppDbContext>((serviceProvider, sqlOpt) =>
    {
        sqlOpt.UseInternalServiceProvider(serviceProvider)
              .UseSqlServer(
                  connectionString,
                  // Make sure thge migration table is also in that schema
                  opt => opt.MigrationsHistoryTable("__EFMigrationsHistory", yourSchema));
    });

并创建一个新类:

/// <summary>
/// A class injected into the SQL command generation
/// in order to replace the schema with the one we want.
/// </summary>
public sealed class SchemaMigrationsSqlGenerator : IMigrationsSqlGenerator
{
    #region Fields

    private readonly MigrationsSqlGenerator mOriginal;

    private readonly ISchemaStorage mSchema;

    #endregion


    #region Init aned clean-up

    /// <summary>
    /// Constructor for dependency injection.
    /// </summary>
    /// <param name="original">Previously used SQL generator</param>
    /// <param name="schema">Where the schema name is stored</param>
    public SchemaMigrationsSqlGenerator(MigrationsSqlGenerator original, ISchemaStorage schema)
    {
        mOriginal = original;
        mSchema = schema;
    }

    #endregion


    #region IMigrationsSqlGenerator API

    /// <inheritdoc />
    /// <remarks>
    /// Overwrite the schema generated during Add-Migration,
    /// then call the original SQL generator.
    /// </remarks>
    IReadOnlyList<MigrationCommand> IMigrationsSqlGenerator.Generate(
        IReadOnlyList<MigrationOperation> operations, IModel model)
    {
        foreach (var operation in operations)
        {
            switch (operation)
            {
                case SqlServerCreateDatabaseOperation _:
                    break;

                case EnsureSchemaOperation ensureOperation:
                    ensureOperation.Name = mSchema.Schema;
                    break;

                case CreateTableOperation tblOperation:
                    tblOperation.Schema = mSchema.Schema;
                    break;

                case CreateIndexOperation idxOperation:
                    idxOperation.Schema = mSchema.Schema;
                    break;

                default:
                    throw new NotImplementedException(
                        $"Migration operation of type {operation.GetType().Name} is not supported by SchemaMigrationsSqlGenerator.");
            }
        }

        return mOriginal.Generate(operations, model);
    }

    #endregion
}

上面的代码强制迁移在注入了普通ISchemaStorage接口的架构中执行。