实体框架核心同一个DBContext上的多个连接字符串?

use*_*433 9 asp.net entity-framework asp.net-core

我有一个带有Entity Framework Core的Asp.Net Core应用程序,我初始化如下:

services.AddDbContext<ApplicationDbContext>(options => 
         options.UseSqlServer(sqlConnectionString));
Run Code Online (Sandbox Code Playgroud)

这工作正常,但我有一个场景,我需要从主数据库读取/写入正常操作,但对于某些操作,我需要从备用服务器(一个只读我们用于报告的复制目标)读取.

通过新的Core API通过依赖注入和StartUp.cs中的配置完成所有工作的方式,如何切换连接字符串,但使用相同的ApplicationDbContext类?

我知道有一个选项可能是我使用不同的连接字符串向DI系统注册的ApplicationDbContext类的副本,但是我想避免维护两个相同的DBContext对象,因为有时我需要从不同的数据库中读取服务器(但具有完全相同的架构).

提前感谢任何指针!

tra*_*.js 14

你需要两个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
{

}
Run Code Online (Sandbox Code Playgroud)

你可以这样注册:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyBloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddDbContext<MyBackupBloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("BackupConnection")));

}
Run Code Online (Sandbox Code Playgroud)

  • 上述方法永远不会起作用,因为我们需要传递 MyBloggingContext 和 MyBackUpBloggingContext 的参数化构造函数。 (4认同)
  • @Siddharth 是对的。为了使其工作,我们需要这样做:仅对基本(BloggingContext)构造函数使用“DbContextOptions”(而不是“DbContextOptions&lt;BloggingContext&gt;”),对 MyBloggingContext 构造函数使用“DbContextOptions&lt;MyBloggingContext&gt;”,对 MyBackupBloggingContext 使用“DbContextOptions&lt;MyBackupBloggingContext&gt;”构造函数。希望这对大家有帮助。 (4认同)

Hyp*_*ngo 12

可以这样完成(使用.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) { }
}
Run Code Online (Sandbox Code Playgroud)

在 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")));

}
Run Code Online (Sandbox Code Playgroud)


pwr*_*imo 8

连接字符串可以使用 来解析IServiceProvider。在下面的示例中,我将查询参数映射到配置appsettings.json,但您可以注入任何您想要的其他逻辑。

services.AddDbContext<ApplicationDbContext>((services, optionsBuilder) =>
{
    var httpContextAccessor = services.GetService<IHttpContextAccessor>();
    var requestParam = httpContextAccessor.HttpContext.Request.Query["database"];

    var connStr = Configuration.GetConnectionString(requestParam);

    optionsBuilder.UseSqlServer(connStr);
});
Run Code Online (Sandbox Code Playgroud)

?database=Connection1并且 ?database=Connection2在查询中会导致使用不同的连接字符串。当参数丢失时,值得提供默认值。