TheGreatZab
TheGreatZab

Reputation: 163

Change Database Schema Name at Runtime

Currently, in my entity I have the following table definition:

[Table("SchemaName.SomeTable")]

I need to be able to change this schema name at run-time. I tried assigning a variable however it throws an error.

As a second attempt I removed the Table declaration and instead in the OnModelCreating of my context tried to set it with the following:

modelBuilder.Entity<MY_VIEW>().ToTable("MYSCHEMA.MYVIEW");

This works, however, I would now like to be able to change this at run time through my controller as OnModelCreating only fires once.

Upvotes: 0

Views: 299

Answers (1)

Kahbazi
Kahbazi

Reputation: 15015

In order to make OnModelCreating to run for different schema you need to override the default behavior for IModelCacheKeyFactory

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
        {
            options.ReplaceService<IModelCacheKeyFactory, SchemaModelCacheKeyFactory>();
        });
    }
}

public class DatabaseOptions
{
    public string Schema { get; set; }
}

public class ApplicationDbContext : DbContext
{
    public string Schema { get; }

    public ApplicationDbContext(DbContextOptions options, IOptions<DatabaseOptions> databaseOptions)
        : base(options)
    {
        Schema = databaseOptions.Value.Schema;
    }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MY_VIEW>().ToTable($"{Schema}.MYVIEW");
    }
}

public class SchemaModelCacheKeyFactory : ModelCacheKeyFactory
{
    public SchemaModelCacheKeyFactory(ModelCacheKeyFactoryDependencies dependencies)
        : base(dependencies)
    {
    }

    public override object Create(DbContext context)
    {
        if (context is ApplicationDbContext applicationDbContext)
        {
            return new SchemaModelCacheKey(context, applicationDbContext.Schema);
        }
        else
        {
            return base.Create(context);
        }
    }
}

public class SchemaModelCacheKey : ModelCacheKey
{
    public SchemaModelCacheKey(DbContext context, string schema) : base(context)
    {
        _schema = schema;
    }

    private readonly string _schema;

    protected virtual bool Equals(SchemaModelCacheKey other) => _schema == other._schema && base.Equals(other);

    public override bool Equals(object obj) => (obj is SchemaModelCacheKey otherAsKey) && Equals(otherAsKey);

    public override int GetHashCode() => base.GetHashCode() + _schema.GetHashCode();
}

Upvotes: 0

Related Questions