类型的 DbContext 不能被合并,因为它没有接受单个 DbContextOptions 类型参数的 public 构造函数

The DbContext of type cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions

我正在尝试将我们当前的 .Net Core 应用程序从 1.1 升级到 2.0,但收到此 运行 时间错误:"The DbContext of type 'CoreContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions".

这是使用新的IServiceCollection.AddDbContextPool<>函数引起的。当我使用 IServiceCollection.AddDbContext<> 时它仍然有效。

此应用程序是 DB-First,因此我使用 'Scaffold-DbContext' 生成我们所有的上下文。因此,以及注入其他服务的需要,我在每个上下文中都有一个扩展,如下所示:

public partial class CoreContext
{
    public CoreContext(
        DbContextOptions<CoreContext> options,
        IUserService userService,
        IAuditRepository auditRepository
        ) : base(options) {...}
}

每当我 运行 Scaffold-DbContext 我只是从 CoreContext 中删除自动生成的构造函数,但即使我把它放在那里我仍然会收到这个错误。

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

我已经将 Program.cs 更新为新样式:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();
}

Startup.cs 非常简单:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    ...
    services.AddDbContextPool<CoreContext>(options => options.UseSqlServer(absConnectionString));
    ...
}

如果有帮助,我正在使用 Autofac 进行 DI。现在我将默认返回到非池化替代方案,但利用此功能会很好。

尝试使用 AddDbContext 而不是 AddDbContextPool。这在同样的情况下帮助了我。 services.AddDbContext<CoreContext>(options => options.UseSqlServer(absConnectionString));

"because it does not have a single public constructor accepting a single parameter of type DbContextOptions"

如果除了接受 DbContextOptions 的构造函数之外还有任何 public 构造函数,您需要删除它们或使它们成为非 public 以便使用上下文池。

此外,通过重写 OnConfiguring 方法可以执行的操作也有限制。此处的文档中引用了这一点,但并未明确说明这些限制是什么:https://docs.microsoft.com/en-us/ef/core/what-is-new/index#dbcontext-pooling

使用 DbContext Pooling 时,您在派生 DbContext class 中的状态(例如私有字段)将被保留。这意味着您的服务生命周期现在是 singleton。这就是为什么你不应该在这里有其他注入的服务。 但是可以通过这种方式查询所需的服务: 首先,我们应该在 DbContextOptionsBuilder 上使用 UseInternalServiceProvider 方法来告诉 EF 为其服务使用哪个服务提供商。此服务提供者必须为 EF 和任何提供者配置所有服务。所以我们应该手动注册 EF 服务:

services.AddEntityFrameworkSqlServer();

然后介绍应用程序的服务提供者,现在也包括 EF 服务:

services.AddDbContextPool<ApplicationDbContext>((serviceProvider, optionsBuilder) =>
{
   optionsBuilder.UseSqlServer("...");
   optionsBuilder.UseInternalServiceProvider(serviceProvider);
});

之后定义这些命名空间:

using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;

现在您可以在应用程序中访问已注册的服务 ApplicationDbContext class 使用以下方法

var siteSettings = this.GetService<IOptionsSnapshot<SiteSettings>>();

var siteSettings = this.GetInfrastructure().GetRequiredService<IOptionsSnapshot<SiteSettings>>();

this 是 DbContext 的当前实例。

这个问题主要发生在你“Scaffold-Dbcontext”生成两个构造函数的时候。

简单的解决方案:

  1. AddDbContextPool: 如果您想使用 AddDbContextPool,请删除您的空构造函数并使用 DbContextOptionsBuilder 维护该构造函数。请注意,在这种情况下,您可能必须按照之前帖子中的建议提供选项。

  2. AddDbContext: 使用 AddDbContext,您可以同时拥有 constructors/Overloads

注意:出于性能原因,AddDbContextPool是首选!

删除 DbContext 中的默认构造函数 class,这对我有用