【问题标题】:EF Core execute against different databases with identical schemaEF Core 对具有相同架构的不同数据库执行
【发布时间】:2020-10-15 07:41:33
【问题描述】:

编辑:我也有一个完全不同的方法,我几乎所有的废话都被注释掉了。我可以调用我的方法并将连接字符串配置为连接到服务器,但不连接到数据库。然后我想根据传入的一些数据(比如数据库名称?)连接到不同的数据库。有没有办法即时调用 OnConfiguring 以便我可以在每次调用方法时将连接字符串配置为不同?

我知道你们中的一些人会看到这个并用我的愚蠢翻白眼,但我们都必须从某个地方开始!我有一个使用一个数据库服务器但多个数据库共享相同架构的场景。目前我正在为每个数据库重写代码,它很乱,所以我试图清理它。我在这里很困惑,所以我正在寻找你们中的一些大师的建议。我是这里的初学者,正在尝试做一些我觉得在这里非常先进的事情,所以请放轻松。我将只使用两个数据库来保留我的示例,但实际上有 10 多个数据库都是相同的,我需要经常在它们之间切换。我的目标是当我想保存或访问记录时,尝试在所有地方摆脱这些 1、2、3、4、9、10 等东西,并让一个东西控制一切。

我为我的数据库上下文创建了一个基类

public partial class opkDataBaseContext : DbContext
{
    private DbContextOptions<opkData1Context> options1;
    private DbContextOptions<opkData2Context> options2;

    public opkDataBaseContext()
    {
    }

    public opkDataBaseContext(DbContextOptions<opkDataBaseContext> options)
        : base(options)
    {
    }

    public opkDataBaseContext(DbContextOptions<opkData1Context> options)
    {
        this.options1 = options;
    }

    public opkDataBaseContext(DbContextOptions<opkData2Context> options)
    {
        this.options2 = options;
    }

    public virtual DbSet<OrgUnits> OrgUnits { get; set; }



    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {


...
    }
       OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);


    public void CreateNewOrganization(CreateCompleteOrgViewModel model)
    {
        var nameParameter = new SqlParameter("@TopLevelOrgName", model.Name);
        var codeParameter = new SqlParameter("@Code", model.Code);
        var DbNameParameter = new SqlParameter("@DBName", model.DbCatalog);
        var debugParameter = new SqlParameter("@debug", "0");
        var firstNameParameter = new SqlParameter("@FirstName", model.FirstName);
        var lastNameParameter = new SqlParameter("@LastName", model.LastName);
        var userNameParameter = new SqlParameter("@Username", model.UserName);

        this.Database.ExecuteSqlRaw("CreateRootOrg @TopLevelOrgName, @Code, @DBName, @debug, @FirstName, @LastName, @Username",
            nameParameter, codeParameter, DbNameParameter, debugParameter, firstNameParameter, lastNameParameter, userNameParameter);

    }

这是我的 Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        if (_env.IsProduction())
        {
            var opkCoreConnection = Configuration.GetConnectionString("opkCoreDatabase");
            services.AddDbContext<opkCoreContext>(options => options.UseSqlServer(opkCoreConnection));

            var opkData1Connection = Configuration.GetConnectionString("opkData1Database");
            services.AddDbContext<opkData1Context>(options => options.UseSqlServer(opkData1Connection));

            var opkData2Connection = Configuration.GetConnectionString("opkData2Database");
            services.AddDbContext<opkData2Context>(options => options.UseSqlServer(opkData2Connection));


            var opkDataLocalBaseConnection = Configuration.GetConnectionString("opkDataBaseDatabase");
            services.AddDbContext<opkDataBaseContext>(options => options.UseSqlServer(opkDataLocalBaseConnection));

然后我为每个数据库设置一个:

    public partial class opkData1Context : opkDataBaseContext
{
    public opkData1Context()
    {
    }

    public opkData1Context(DbContextOptions<opkData1Context> options)
        : base(options)
    {
    }

我目前的错误是:

“验证服务描述符'ServiceType: Models.DataModels.opkDataBaseContext Lifetime: Scoped ImplementationType: Models.DataModels.opkDataBaseContext'时出错: 无法激活类型'Models.DataModels.opkDataBaseContext'。以下构造函数不明确:\r \nVoid .ctor(Microsoft.EntityFrameworkCore.DbContextOptions'1[Models.DataModels.opkDataBaseContext])\r\nVoid .ctor(Microsoft.EntityFrameworkCore.DbContextOptions'1[Models.opkData1Context])"} System.Exception {System.InvalidOperationException}

我整天都在搞这个。首先,我是否走上了正确的道路,或者这只是一个愚蠢的想法?其次,知道我哪里出错了吗?谢谢!

【问题讨论】:

  • 应用需要并行使用多个数据库?
  • 数据库之间的切换是如何发生的?
  • 感谢您的回复。涉及多个数据库,但我一次只根据我的视图中的选择将数据保存到其中一个。它们具有相同的架构。不过,我正在做某事。我想出创建一个基类,我可以使用 OnConfiguring 来更改我的数据库上下文,并且可以访问正确的数据库。我现在卡住的地方是我不知道如何将值传递给基本上下文构造函数,因此我可以控制在 OnConfiguring 中更改为哪个数据库。

标签: c# entity-framework asp.net-core entity-framework-core asp.net-core-3.1


【解决方案1】:

我有一个场景,只有一台数据库服务器,但多个数据库共享相同的架构

这在软件即服务 (SaaS) 应用程序中非常普遍,甚至是最佳实践。

虽然这并不明显,但事实证明它非常简单。您只需要某种方式在运行时选择连接字符串,可能基于配置和 HttpContext 中的某些内容(如用户身份、路径、主机头等)的组合。然后像这样为 DI 配置 DbContext:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();

        services.AddDbContext<MyDbContext>((sp, opt) =>
        {
            var httpContext = sp.GetRequiredService<IHttpContextAccessor>();
            var config = sp.GetRequiredService<IConfiguration>();

            string connectionString = GetConnectionStringFromHttpContext(httpContext, config);

            opt.UseSqlServer(connectionString, o => o.UseRelationalNulls());

        });

        services.AddControllers();
    }

GetConnectionStringFromHttpContext 是一个自定义方法,它基于配置和 HttpContext 构建连接字符串。

【讨论】:

  • 谢谢。在发布后不久,我靠着魔法和运气非常接近您的答案。我仍在努力。我废弃了这么多代码和这么多文件。这对我来说并不完全“容易”,但我确实发现我可以使用 HttpContext 传递我的数据库名称,然后在我的基础数据库类的 OnConfiguring 方法中更改连接字符串。太赞了!今天学习了很多。 =)
【解决方案2】:

你可以看看EF Core 5中引入的一个特性,它可以改变已经初始化的上下文中的连接或连接字符串

【讨论】:

  • 我确实读过 ef5 有这个,但我试图坚持使用 3.1,因为我对这整个语言仍然很陌生。我不想有额外的复杂层来处理像 ef5 目前拥有的更少的文档。我需要我能得到的所有帮助!
  • 你已经经历过stackoverflow.com/questions/36816215/… - 不喜欢其中任何一个的外观?
  • 我确实看过这些并最终确实使用了 HttpContext 的想法(类似于我从上面接受的答案)。我现在有一个效果很好的解决方案。所以现在他们可以添加任意数量的数据库,我将能够连接到他们!
猜你喜欢
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多