如何在控制器中使用多个 DBContext

Posted

技术标签:

【中文标题】如何在控制器中使用多个 DBContext【英文标题】:How to use more than one DBContext in a controller 【发布时间】:2021-07-01 03:38:08 【问题描述】:

,我试图以不同的方式重载构造函数?

一些控制器:

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

我找到了this,但是好像已经过时了

Error(, 前端调用构造函数时):

执行请求时发生未处理的异常。

异常:System.InvalidOperationException:DbContextOptions 传递给 DBContext1 构造函数必须是 DbContext 选项。注册多个 DbContext 时 类型确保每个上下文类型的构造函数都有 DbContextOptions 参数而不是非泛型 DbContextOptions 参数。在 Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions 选项)在_4_DWH.DBContext1..ctor(DbContextOptions选项)中 D:...\DBContext1.cs:第 43 行 System.RuntimeMethodHandle.InvokeMethod(对象目标,对象 [] 参数、签名 sig、布尔构造函数、布尔 wrapExceptions) 在 System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr、Binder binder、Object[] 参数、CultureInfo 文化) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite,RuntimeResolverContext 上下文)在 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 参数)在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite,ServiceProviderEngineScope 范围)在 Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.c__DisplayClass1_0.b__0(ServiceProviderEngineScope 范围)在 Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(类型 serviceType, ServiceProviderEngineScope serviceProviderEngineScope) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(类型 服务类型)在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) 在 lambda_method(Closure, IServiceProvider, Object[]) 在 Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.c__DisplayClass4_0.b__0(ControllerContext 控制器上下文)在 Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.c__DisplayClass5_0.g__CreateController|0(ControllerContext 控制器上下文)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(状态& next, Scope& 范围, Object& 状态, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔值 已完成)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed 上下文)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(状态& next, Scope& 范围, Object& 状态, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker 调用者、任务任务、IDisposable 范围)在 Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(端点 端点,任务 requestTask,ILogger 记录器)在 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)

数据库上下文:

public class DBContext1 : DbContext

    // ...

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

    public DBContext1() : base()
    

    

    public DBContext1(DbContextOptions options) : base(options)
    
    

【问题讨论】:

这个:***.com/questions/56937314/… 对你有帮助吗? 为什么这还不起作用?显示一个屏幕截图,说明问题/您如何知道存在问题。向我们展示创建控制器的任何代码(它不应该;DI 应该这样做)。向我们展示控制器 DI 注册。向构造函数显示参数的值。告诉我们任何错误信息 见下文:***.com/questions/13291025/… @all 更新了我的帖子 您需要使用DbContextOptions&lt;DbContext1&gt;DbContextOptions&lt;DbContext2&gt; ... 而不仅仅是DbContextOptions(在构造函数中)。 【参考方案1】:
    创建数据库上下文
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)
    
    

    为每个 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;...",
  

    在启动时注册:
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"));
);

    注入控制器:
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;
    

代码优先方法的其他最佳实践:

为每个上下文创建一个类库,因此当您应用迁移时,每个上下文将在其自己的项目中拥有自己的迁移文件夹。

解决方案 主要项目 startup.cs 类库_A DbContext_A.cs 迁移 // 文件夹 类库_B DbContext_B.cs 迁移 // 文件夹 类库_C DbContext_C.cs 迁移 // 文件夹

在多上下文解决方案中应用迁移时;

在解决方案资源管理器中,将主项目(带有 startup.cs)设置为“启动项目” 将包管理器控制台中的相关 ClassLibrary_A 或 B 或 C 设置为“默认项目” 将目标上下文添加到每个 cmd,如下所示:
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

或者,您可以使用完整的 PM cmd,如下所示:

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

【讨论】:

以上是关于如何在控制器中使用多个 DBContext的主要内容,如果未能解决你的问题,请参考以下文章

如何使用autofac实现多个DbContext的注入

实体框架:如何防止 dbcontext 被多个线程访问?

如何在 EF Core 中实例化 DbContext

DBContext更改后如何在控制器内创建新的UserManager对象

如何在静态方法或控制器外的类中获取applicationDbContext的dbContext

如何在 DDD 中使用 EF DbContext 分离我的聚合