I have an Asp.Net Core app with Entity Framework Core that I initialize as follows:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(sqlConnectionString));
This works fine, but I have a scenario where I need to read/write from the primary database for normal operations but for some operations I need to read from an alternate server (a replication target that's read only that we use for reporting).
With the way the new Core API does everything via Dependency Injection and configuration in StartUp.cs, how do I switch connection strings, but use the same ApplicationDbContext class?
I know that one option would be to have a duplicate of ApplicationDbContext class that I register with the DI system using a different connection string, but I'd like to avoid maintaining two identical DBContext objects just because sometimes I need to read from a different database server (but with the exact same schema).
Thanks in advance for any pointers!
A DbContext only supports a single open data reader at any point in time. If you want to execute multiple simultaneous database queries you will need multiple DbContext instances, one for each concurrent query.
Multiple DbContext was first introduced in Entity Framework 6.0. Multiple context classes may belong to a single database or two different databases.
1 Answer. First, DbContext is a lightweight object; it is designed to be used once per business transaction. Making your DbContext a Singleton and reusing it throughout the application can cause other problems, like concurrency and memory leak issues. And the DbContext class is not thread safe.
But if you use other injected services, with "transient" on the DBContext, every service gets his own instance of it. In order to avoid that you should always use "scoped" on the DBContext. Save this answer.
You'll need two DbContexts.
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class MyBloggingContext : BloggingContext
{
}
public class MyBackupBloggingContext : BloggingContext
{
}
And you can register them like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyBloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<MyBackupBloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BackupConnection")));
}
Can be done like this(tested with .net core 3.1):
public abstract partial class BloggingContext<T> : DbContext where T : DbContext
{
private readonly string _connectionString;
protected BloggingContext(string connectionString) { _connectionString = connectionString; }
protected BloggingContext(DbContextOptions<T> options) : base(options) { }
public virtual DbSet<Blog> Blogs { get; set; }
public virtual DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
}
}
public class MyBloggingContext : BloggingContext<MyBloggingContext>
{
public MyBloggingContext(string connectionString) : base(connectionString) { }
public MyBloggingContext(DbContextOptions<MyBloggingContext> options) : base(options) { }
}
public class MyBackupBloggingContext : BloggingContext<MyBackupBloggingContext>
{
public MyBackupBloggingContext(string connectionString) : base(connectionString) { }
public MyBackupBloggingContext(DbContextOptions<MyBackupBloggingContext> options) : base(options) { }
}
And in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyBloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<MyBackupBloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BackupConnection")));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With