.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.
我想在 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.