Sacha K
Sacha K

Reputation: 642

How to have multiple DbContext of the same type?

I want to do some reporting in a ASP.NET Core web site that reads data from multiple databases using the same schema.

In Startup.cs I need to have something like:

public void ConfigureServices(IServiceCollection services)
{

// Some other stuff here.

services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FirstConnectionString")));
services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondConnectionString")));

}

But now the DbContext are of the same type and have no name, so how do I select the one I want to use in a controller?

public class HomeController : Controller
{

    private readonly MyContext context;

    public HomeController(MyContext context)
    {
        // Is that the one with FirstConnectionString or SecondConnectionString?
        // How do I choose?
        this.context = context;
    }

}

EDIT:

I'm probably missing something but in MyContext I have:

public class MyContext : DbContext
{

    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    // Some more code here.

}

Then in MyContext1 I have:

public class MyContext1 : MyContext
{

    // base in now MyContext and not DbContext !!!
    // Error with: public MyContext1(DbContextOptions<MyContext1> options) : base(options)
    public MyContext1(DbContextOptions<MyContext> options) : base(options)
    {
    }

}

If I add 2 derived types in startup and run it crashes and gives the following error message:

InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MyContext]' while attempting to activate 'MyContext1'.

If I also add the base type in startup (so 3 types with 3 different connection strings) then all 3 types use the connection string of the base type.

Upvotes: 3

Views: 1679

Answers (2)

Gibbon
Gibbon

Reputation: 2773

Why not just create two DbContexts? In theory, making 3 is probably cleaner .. keep the MyContext that you have set up, and then just create a Db1Context and Db2Context that inherit from it? means your registration ends up as

services.AddDbContext<Db1Context>(options => options.UseSqlServer(Configuration.GetConnectionString("FirstConnectionString")));
services.AddDbContext<Db2Context>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondConnectionString")));

so then its easy to resolve, and due to inheritance you avoid some code duplication.. but I see no benefit from trying to keep 1 dbcontext that goes to multiple db in the same app

Edit: If you are still having some troubles with DI working, there was a fairly old thread on the Github that looks like someone having this type of issue which they resolved by doing

public class EFDbContext : DbContext
    {
        public EFDbContext(DbContextOptions<EFDbContext> options) : base(options) { }
        protected MainDbContext(DbContextOptions options) : base(options) { }
    }

public class DimensionsDbContext : EFDbContext
    {
        public DimensionsDbContext(DbContextOptions<DimensionsDbContext> options) : base(options) { }
    }

something along those lines, having a second protected constructor in the class that inherits from dbcontext, to allow for the further inherited classes to use that. I mean, I wasnt able to re-create the issue on my end but that solution still also works for me, so may help in terms of getting it working for you

Upvotes: 5

Sacha K
Sacha K

Reputation: 642

I'm creating the multiple contexts in my reporting controllers in the end. It's not the DI way, but it works.

I have something like the following code in the controller constructor:

var firstOptionsBuilder = new DbContextOptionsBuilder<MyContext>();
firstOptionsBuilder.UseSqlServer("firstConnectionString");
var firstContext = new MyContext(firstOptionsBuilder.Options);

Upvotes: -1

Related Questions