具有多个数据库上下文的.NET Core应用程序不会在所有DbContext中生成表 [英] .NET Core app with multiple database contextes does not generate tables in all DbContexts

查看:45
本文介绍了具有多个数据库上下文的.NET Core应用程序不会在所有DbContext中生成表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经制作了一个带有 .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.

有两种解决方法:

  1. 将数据库拆分为两个.这是EntityFramework最喜欢的解决方案.

但是,如果没有选择,请查看:

However, if it's not an option, look into:

  1. 查看 IRelationalDatabaseCreator.CreateTables()方法:

https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.storage.irelationaldatabasecreator?view=efcore-5.0

这是一个可能的解决方案:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆