fass33443423
fass33443423

Reputation: 117

How to use more than one DBContext in a controller

How to use more than one DBContext in a controller, I tried to overload the construktors in different ways?

Some Controller:

public C1(DBContext1 a, DBContext2 b, DBContext3 c)
{ 
}
 //public C1(DBContext1 a)
 //{ 
 //}
 //public C1(DBContext2 b)
 //{
 //}
 //public C1(DBContext3 c)
 //{
 //}

StartUp.cs:

services.AddDbContext<DBContext1>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

services.AddDbContext<DBContext2>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

services.AddDbContext<DBContext3>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

I found this, but it seems to be outdated

Error(, when Calling the constructor by the frontend):

An unhandled exception has occurred while executing the request.

Exception: System.InvalidOperationException: The DbContextOptions passed to the DBContext1 constructor must be a DbContextOptions. When registering multiple DbContext types make sure that the constructor for each context type has a DbContextOptions parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at _4_DWH.DBContext1..ctor(DbContextOptions options) in D:...\DBContext1.cs:line 43 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.b__0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

DBContext:

public class DBContext1 : DbContext
{
    // ...

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(new string(sameConnectionString));
    }

    public DBContext1() : base()
    {

    }

    public DBContext1(DbContextOptions options) : base(options)
    {
    }
}

Upvotes: 2

Views: 3326

Answers (1)

LazZiya
LazZiya

Reputation: 5729

  1. Create DB contexts
public class DBContext_A : DbContext
{
    public DBContext_A(DbContextOptions<DBContext_A> options) : base(options)
    {
    }
}

public class DBContext_B : DbContext
{
    public DBContext_B(DbContextOptions<DBContext_B> options) : base(options)
    {
    }
}

public class DBContext_C : DbContext
{
    public DBContext_C(DbContextOptions<DBContext_C> options) : base(options)
    {
    }
}
  1. Define a connection string for each DBContext:
{
  "ConnectionStrings": {
    "Connection_A": "Server=(localdb)\\mssqllocaldb;Database=DB_A;Trusted_Connection=True;...",
    "Connection_B": "Server=(localdb)\\mssqllocaldb;Database=DB_B;Trusted_Connection=True;...",
    "Connection_C": "Server=(localdb)\\mssqllocaldb;Database=DB_C;Trusted_Connection=True;...",
  }
}
  1. Register in startup:
services.AddDbContext<DBContext_A>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_A"));
});

services.AddDbContext<DBContext_B>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_B"));
});

services.AddDbContext<DBContext_C>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_C"));
});

  1. Inject into controller:
public FooController : Controller
{
    private readonly DBContext_A _context_A;
    private readonly DBContext_B _context_B;
    private readonly DBContext_C _context_C;

    public FooController(
            DBContext_A context_A, 
            DBContext_B context_B, 
            DBContext_C context_C)
    {
        _context_A = context_A;
        _context_B = context_B;
        _context_C = context_C;
    }
}

Additional best-practice for Code First approach:

Create a class library for each context, so when you apply migrations each context will have its own migrations folder in its own project.

  • Solution
    • MainProject
      • startup.cs
    • ClassLibrary_A
      • DbContext_A.cs
      • Migrations // folder
    • ClassLibrary_B
      • DbContext_B.cs
      • Migrations // folder
    • ClassLibrary_C
      • DbContext_C.cs
      • Migrations // folder

While applying migrations in a multi context solution;

  • From solution explorer, Set the main project (with startup.cs) as "Startup project"
  • Set the relevant ClassLibrary_A or B or C from the package manager console as "Default project"
  • Add the target context to each cmd as below:
PM > add-migration Init -Context DBContext_A
PM > update-database -Context DBContext_A

PM > add-migration Init -Context DBContext_B
PM > update-database -Context DBContext_B

PM > add-migration Init -Context DBContext_C
PM > update-database -Context DBContext_C

Alternatively, you may use the full PM cmd as below:

PM > add-migration Init -Context DBContext_A -Project ClassLibrary_A -StartupProject MainProject
PM > update-database -Context DBContext_A -Project ClassLibrary_A -StartupProject MainProject

PM > add-migration Init -Context DBContext_B -Project ClassLibrary_B -StartupProject MainProject
PM > update-database -Context DBContext_B -Project ClassLibrary_B -StartupProject MainProject

PM > add-migration Init -Context DBContext_C -Project ClassLibrary_C -StartupProject MainProject
PM > update-database -Context DBContext_C -Project ClassLibrary_C -StartupProject MainProject

Upvotes: 3

Related Questions