使用 Entityframework Core,如何在不更改连接字符串的情况下动态更改我连接的 MySql 数据库?

Posted

技术标签:

【中文标题】使用 Entityframework Core,如何在不更改连接字符串的情况下动态更改我连接的 MySql 数据库?【英文标题】:Using Entityframework Core, how can I dynamically change the MySql database, I connect to, without changing the connection string? 【发布时间】:2021-12-17 07:28:30 【问题描述】:

我在我的asp.net 5 应用程序中使用Pomelo Entity framework coremysqlConnector 连接到我的MySql 数据库 - 使用自定义 DbContext 类。这通常工作正常。

但是,我需要连接到连接字符串中的数据库以外的另一个数据库(例如“INFORMATION_SCHEMA”)。

我当然可以更改连接字符串,替换数据库名称,但是:

这会创建一个额外的连接池 - 每个连接字符串一个!

我试图避免这种情况 - 每个网站只有一个连接池。

我在搞乱“SetDefaultSchema”和其他尝试都失败了。

如何更改数据库名称,DbContext 使用所以我只有一个连接池,但每个 DbContext 都有自己的数据库要连接?

【问题讨论】:

所有 ORM,包括 EF Core 都在幕后使用旧的好 ADO.NET(还有什么?)。 DbConnection 需要 - 你知道,连接字符串。 是的,但至少在 MySql 中您可以更改已打开连接的数据库。 怎么样?你能用 MySQL ADO.NET 连接对象做到这一点吗?或者您的意思是在 SELECT 和其他 DML SQL 命令中将 SCHEMA 附加到表名?如果是后者,那么他们(Pomelo 维护者)似乎特别不想允许这样做 - 请参阅他们的 GitHub 线程 github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/… 和相关链接 @IvanStoev:你说得对,'Schema' 与 MySql 不兼容,这就是我第一次尝试失败的原因(也是 Pomelo 放弃它的原因)。解决方法如下。 【参考方案1】:

解决方案实际上很简单:使用连接拦截器(可从 Entity Framework Core 3.0+ 获得)。

下面的代码连接打开后切换数据库。 现在每个DbContext 类都可以使用自己的数据库,并且只使用一个连接池。

首先创建一个继承自DbConnectionInterceptor 的拦截器类。构造函数将要切换到的数据库名称作为参数:

using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Data.Common;
using System.Threading.Tasks;

public class MySqlConnectionInterceptor : DbConnectionInterceptor

    public MySqlConnectionInterceptor(string databaseName)
    
        database = databaseName;
    

    readonly string database;

    public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData)
    
        if (database != null)
        
            connection.ChangeDatabase(database); // The 'magic' code
        
        base.ConnectionOpened(connection, eventData);
    

    public override async Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
    
        if (database != null)
        
            await connection.ChangeDatabaseAsync(database); // The 'magic' code
        
        await base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
    


现在您只需在 DbContext 类的 OnConfiguring 方法中包含一行:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)


    optionsBuilder.AddInterceptors(new MySqlConnectionInterceptor("yourDatabase"));

现在连接每次都会切换到“yourDatabase”数据库,它已打开。

而且它只会使用一个连接池(总计)!这样,“休眠”连接的数量就会保持在最低限度。

之所以有效,是因为 Pomelo Entity Framework Core 总是在从池中重用连接之前重置连接(除非您专门设置了 'Connectionreset=false' - 无论如何这很糟糕)。它将数据库设置回连接字符串中的那个,您当然可以再次覆盖它)。

当然,您不必对数据库名称进行硬编码。例如,如果您使用基类 DbContext 类,您的其他 DbContexts 继承自该类,则可以创建一个将数据库名称作为参数的构造函数,如下所示:

public class BaseDbContext : DbContext

    public BaseDbContext (string databaseName)
    
        database = databaseName;
    

    string database;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    
    
        optionsBuilder.AddInterceptors(new MySqlConnectionInterceptor(database));
    

代码已在 Asp.Net 5+6 和 .Net Windows Forms 中测试。

【讨论】:

以上是关于使用 Entityframework Core,如何在不更改连接字符串的情况下动态更改我连接的 MySql 数据库?的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core005EntityFramework的使用

.Net Core005EntityFramework的使用

使用 entityFramework Automapper .Net Core 的嵌套映射

带有标识 2 和 EntityFramework 6(Oracle)的 ASP.NET Core MVC

使用泛型类型执行 EntityFramework Core LINQ 查询

EntityFramework Core 中的映射继承