.NET Core 2 与 EF Core 在同一数据库中具有不同架构的不同上下文(SQL 服务器)

.NET Core 2 with EF Core different contexts with different schemas in same DB(SQL Server)

我想在 C# ASP.NET Core 2 应用程序中将我的表放在两个单独的模式中。我在 appsettings.json 中创建了两个单独的数据库上下文和不同的连接字符串。

appsettings.json

"DefaultConnection": "Server=db;Database=DB;User=u;Password=pwd;",
"InventoryCon": "Server=db;Database=DB;User=u;Password=pwd;"

启动:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<CustomerDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddDbContext<InventoryDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("InventoryCon")));

    services.AddMvc();
}

我在每个 dbContextClasses 中指定默认模式: 库存:

...protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("inventory");
}

客户:

...protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("customer");
}

在程序中,我尝试同时播种:

public static void Main(string[] args)
{
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<CustomerDbContext>();
            DbInitializer.Initialize(context);

        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding Customer database.");
        }

        try
        {
            var contexti = services.GetRequiredService<InventoryDbContext>();
            DbInitializer.InitInventory(contexti);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding Inventory database.");
        }
    }

    host.Run();
}

如果连接字符串指向不同的数据库,上面的方法工作正常,所以我猜它有两个连接字符串指向同一个数据库的问题。理想情况下,我可以将这些表分离到单独的模式中,这样我就可以更好地控制查询访问。

关于如何将我的表分成不同模式的任何想法?

编辑:添加错误:

info: Microsoft.EntityFrameworkCore.Infrastructure[10403] Entity Framework Core 2.0.1-rtm-125 initialized 'InventoryDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None Microsoft.EntityFrameworkCore.Infrastructure:Information: Entity Framework Core 2.0.1-rtm-125 initialized 'InventoryDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (32ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE') SELECT 1 ELSE SELECT 0 Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (32ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE') SELECT 1 ELSE SELECT 0 'dotnet.exe"' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App.0.4\System.Diagnostics.StackTrace.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'dotnet.exe"' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App.0.4\System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. fail: Microsoft.EntityFrameworkCore.Database.Command[20102] Failed executing DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT CASE WHEN EXISTS ( SELECT 1 FROM [inventory].[DUA] AS [d]) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END System.Data.SqlClient.SqlException (0x80131904): Invalid object name 'inventory.DUA'.

我在为客户创建模式时在日志中注意到以下内容,这在库存中从未发生过: IF SCHEMA_ID(N'customer') IS NULL EXEC(N'CREATE SCHEMA [customer];');

我想说的是,它抱怨两个上下文写入数据库中相同的 'default' 迁移历史记录 table。

要解决这个问题,您需要稍微修改您的服务配置,以便它为您拥有的每个上下文指定不同的迁移 table:

services.AddDbContext<CustomerDbContext>(
                options => options.UseSqlServer(
                    this.Configuration.GetConnectionString("DefaultConnection"),
                    sqlServerOptions => sqlServerOptions.MigrationsHistoryTable("Customer")));

services.AddDbContext<InventoryDbContext>(
                options => options.UseSqlServer(
                    this.Configuration.GetConnectionString("DefaultConnection"),
                    sqlServerOptions => sqlServerOptions.MigrationsHistoryTable("Inventory")));

编辑:修复了代码片段。

我的问题是我将 EF 与 database.EnsureCreated 一起使用,它只检查数据库是否存在,如果不存在,它会为该上下文创建数据库和指定模式。在连续调用中,它会看到数据库但不会创建模式。解释和解决方案由 rowan miller here.