Entity Framework Core 同一 DBContext 上有多个连接字符串?

问题描述 投票:0回答:5

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

services.AddDbContext<ApplicationDbContext>(options => 
         options.UseSqlServer(sqlConnectionString));

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

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

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

提前感谢您的指点!

asp.net entity-framework asp.net-core
5个回答
41
投票

您将需要两个 DbContext。

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class MyBloggingContext : BloggingContext
{

}

public class MyBackupBloggingContext : BloggingContext
{

}

你可以这样注册它们:

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

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

}

13
投票

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

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

}

9
投票

连接字符串可以使用

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);
});
查询中的

?database=Connection1
?database=Connection2
将导致使用不同的连接字符串。当参数丢失时,值得提供默认值。


2
投票

可以这样解决

public class AppDbContext : DbContext
{
    private string _connectionString { get; }

    public AppDbContext(string connectionString, DbContextOptions<AppDbContext> options) : base(options)
    {
        _connectionString = connectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }
}

然后手动创建DbContext

var appDbContext = new AppDbContext("server=localhost;database=TestDB;Trusted_Connection=true", new DbContextOptions<AppDbContext>());

不要对连接进行硬编码,而是从连接字符串工厂读取。


0
投票

虽然这个问题的答案可以正常工作,但由于两个上下文都必须将数据写入两个服务器,因此它们引入了写入延迟。另一种解决方案是使用数据库复制。例如,

postgresql
都具有流式复制和逻辑复制(可以在此处找到设置文章),而SQLite具有LiteFSMarmot

随意搜索您选择的数据库的复制配置,最好遵循该解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.