使用 Entityframework Core,如何在不更改连接字符串的情况下动态更改我连接的 MySql 数据库?
Using Entityframework Core, how can I dynamically change the MySql database, I connect to, without changing the connection string?
我在我的 asp.net 5
应用程序中使用 Pomelo Entity framework core
和 MySqlConnector
连接到我的 MySql
数据库 - 使用自定义 DbContext 类。这通常工作正常。
但是,我需要连接到另一个数据库而不是连接字符串中的数据库(例如 'INFORMATION_SCHEMA')。
我当然可以更改连接字符串,替换数据库名称,但是:
创建一个额外的连接池 - 每个连接字符串一个!
我正在努力避免这种情况 - 每个网站只有一个连接池。
我一直在搞 'SetDefaultSchema' 和其他尝试,但都惨遭失败。
如何更改 DbContext 使用的数据库名称,这样我只有一个连接池,而且每个 DbContext 都有自己的数据库要连接?
解决方法其实很简单:使用连接拦截器(可从Entity Framework Core 3.0+获得)。
下面的代码在 连接打开后 切换数据库。
现在每个 DbContext
class 都可以使用自己的数据库,并且只使用一个连接池。
首先你创建一个拦截器 class 继承自 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
class 的 OnConfiguring
方法中添加一行:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(new MySqlConnectionInterceptor("yourDatabase"));
}
现在每次打开连接都会切换到'yourDatabase'数据库。
而且它只会使用一个连接池(总计)!这样 'sleeping' 连接的数量保持在最低限度。
这是有效的,因为 Pomelo Entity Framework 核心总是在从池中重新使用它之前重置连接(除非你专门设置 'Connectionreset=false' - 这无论如何都是不好的).它将数据库设置回连接字符串中的数据库,您当然可以再次覆盖它)。
当然你不必硬编码数据库名称。例如,如果您使用其他 DbContext 继承自的基础 DbContext
class,则可以创建一个将数据库名称作为参数的构造函数,如下所示:
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 表格中进行测试。
我在我的 asp.net 5
应用程序中使用 Pomelo Entity framework core
和 MySqlConnector
连接到我的 MySql
数据库 - 使用自定义 DbContext 类。这通常工作正常。
但是,我需要连接到另一个数据库而不是连接字符串中的数据库(例如 'INFORMATION_SCHEMA')。
我当然可以更改连接字符串,替换数据库名称,但是:
创建一个额外的连接池 - 每个连接字符串一个!
我正在努力避免这种情况 - 每个网站只有一个连接池。
我一直在搞 'SetDefaultSchema' 和其他尝试,但都惨遭失败。
如何更改 DbContext 使用的数据库名称,这样我只有一个连接池,而且每个 DbContext 都有自己的数据库要连接?
解决方法其实很简单:使用连接拦截器(可从Entity Framework Core 3.0+获得)。
下面的代码在 连接打开后 切换数据库。
现在每个 DbContext
class 都可以使用自己的数据库,并且只使用一个连接池。
首先你创建一个拦截器 class 继承自 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
class 的 OnConfiguring
方法中添加一行:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(new MySqlConnectionInterceptor("yourDatabase"));
}
现在每次打开连接都会切换到'yourDatabase'数据库。
而且它只会使用一个连接池(总计)!这样 'sleeping' 连接的数量保持在最低限度。
这是有效的,因为 Pomelo Entity Framework 核心总是在从池中重新使用它之前重置连接(除非你专门设置 'Connectionreset=false' - 这无论如何都是不好的).它将数据库设置回连接字符串中的数据库,您当然可以再次覆盖它)。
当然你不必硬编码数据库名称。例如,如果您使用其他 DbContext 继承自的基础 DbContext
class,则可以创建一个将数据库名称作为参数的构造函数,如下所示:
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 表格中进行测试。