简体   繁体   中英

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

I would like to have my tables in a C# ASP.NET Core 2 application in two separate schemas. I have created two separate DB contexts and different connection strings in appsettings.json .

appsettings.json

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

startup:

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();
}

I am specifying default schema in each of the dbContextClasses: Inventory:

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

Customer:

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

In Program I am trying to seed both:

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();
}

The above works fine if the connections strings are to different databases so I am guessing it has an issue with two connection strings to the same DB. Ideally I could separate out these tables into separate schemas so I can better control access for queries.

Any ideas on how I can separate my tables into separate schemas?

EDIT: Adding ERROR:

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 \\2.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\\2.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'.

I noticed the following in the logs when it creates the schema for customer, which never happens for inventory: IF SCHEMA_ID(N'customer') IS NULL EXEC(N'CREATE SCHEMA [customer];');

I want to say that its complaining about both contexts writing to the same 'default' migrations history table in the database.

To get around this, you'll need to slightly modify your service configuration so that it specifies different migration tables for each of the contexts you have:

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")));

Edit: Fixed the code snippet.

My issue was I was using EF with database.EnsureCreated which only checks if the database is there and if not it creates the DB and the specified schema for that context. On successive calls it sees the database and does not create the schema. The explanation and solution is by rowan miller here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM