具有多个数据库上下文的.NET Core应用程序不会在所有DbContext中生成表 [英] .NET Core app with multiple database contextes does not generate tables in all DbContexts
问题描述
我已经制作了一个带有 .NET core 3.1
的OData服务器.
I have made an OData server with .NET core 3.1
.
在此应用程序中,我有2个数据库上下文.其中一个用于应用程序本身(AppDbContext),另一个用于帐户管理和身份验证(AccountDbContext).
我有一个像这样的 ServiceExtensions
:
public static class ServiceExtensions
{
public static void ConfigureMySqlContext(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseMySql(configuration.GetConnectionString("MysqlConnection"),
mysqlOptions => {
mysqlOptions.ServerVersion(new ServerVersion(new Version(5, 4, 3), ServerType.MySql));
});
});
services.AddDbContext<AccountDbContext>(options =>
{
options.UseMySql(configuration.GetConnectionString("MysqlConnection"),
mysqlOptions => {
mysqlOptions.ServerVersion(new ServerVersion(new Version(5, 4, 3), ServerType.MySql));
});
});
}
}
在 startup.cs
中,我将调用 ConfigureMySqlContext
函数,如下所示:
And in the startup.cs
I will call the ConfigureMySqlContext
function as following:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime.
// I use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureMySqlContext(Configuration);
}
}
public static class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build()
.CreateDbIfNotExists()
.Run();
}
private static IHost CreateDbIfNotExists(this IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var accountDbContext = services.GetRequiredService<AccountDbContext>();
accountDbContext.Database.EnsureCreated();
var appDbContext = services.GetRequiredService<AppDbContext>();
appDbContext.Database.EnsureCreated();
}
return host;
}
}
此代码的目的是在数据库内部的两个上下文中生成所需的表.问题是,当我将此应用程序发布到服务器时,以及该应用程序首次运行时,它只会生成并初始化 AppDbContext
中的表.为什么?因为它位于 AccountDbContext
之前.
The aim of this code is, to generate the needed tables in both contexts inside the database.
The problem is, when I publish this application to the server, and when the app will run for the first time, it will only generate and initiate the tables that are in the AppDbContext
. Why? Because it is placed before AccountDbContext
.
如果我按照以下方式更改 ConfigureMySqlContext
函数并再次发布该应用程序:
If I change the ConfigureMySqlContext
function as follow and publish the app again:
public static class ServiceExtensions
{
public static void ConfigureMySqlContext(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<AccountDbContext>(options =>
{
options.UseMySql(configuration.GetConnectionString("MysqlConnection"),
mysqlOptions => {
mysqlOptions.ServerVersion(new ServerVersion(new Version(5, 4, 3), ServerType.MySql));
});
});
services.AddDbContext<AppDbContext>(options =>
{
options.UseMySql(configuration.GetConnectionString("MysqlConnection"),
mysqlOptions => {
mysqlOptions.ServerVersion(new ServerVersion(new Version(5, 4, 3), ServerType.MySql));
});
});
}
}
然后将是 AccountDbContext
中的表,该表将在第一次运行后在数据库中启动.
Then it will be the tables inside the AccountDbContext
which will be initiated in the database after the first run.
推荐答案
问题在于, EnsureCreated
的核心是非常简单的语义,可以将其建模为:
The issue is that at it's core, EnsureCreated
has very simple semantics, which can be modeled as:
if (!database.exists()) {
database.create();
}
其中 exists()
会检查数据库是否存在,而不会检查数据库中是否存在表.
where exists()
checks for the existance of the database, without inspecting if the tables inside the database.
最终结果是,如果数据库不是完全为空,则 EnsureCreated()
将无效.
The end result of it is that if the database is not completely empty, EnsureCreated()
will have no effect.
有两种解决方法:
- 将数据库拆分为两个.这是EntityFramework最喜欢的解决方案.
但是,如果没有选择,请查看:
However, if it's not an option, look into:
- 查看
IRelationalDatabaseCreator.CreateTables()
方法:
这是一个可能的解决方案:
Here is a possible solution:
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Infrastructure;
public static class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build()
.CreateDbIfNotExists()
.Run();
}
private static IHost CreateDbIfNotExists(this IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var accountDbContext = services.GetRequiredService<AccountDbContext>();
accountDbContext.Database.EnsureCreated();
var accountDbCreator = accountDbContext.GetService<IRelationalDatabaseCreator>();
accountDbCreator.CreateTables();
}
catch (Exception e) { }
try
{
var appDbContext = services.GetRequiredService<AppDbContext>();
appDbContext.Database.EnsureCreated();
var appDbCreator = appDbContext.GetService<IRelationalDatabaseCreator>();
appDbCreator.CreateTables();
}
catch (Exception e) { }
}
return host;
}
}
这篇关于具有多个数据库上下文的.NET Core应用程序不会在所有DbContext中生成表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!