类型的DbContext无法合并,因为它没有单个公共构造函数接受DbContextOptions类型的单个参数

时间:2017-08-21 19:42:05

标签: asp.net-core entity-framework-core .net-core-2.0

我正在尝试将当前的.Net Core应用程序从1.1升级到2.0并且遇到此运行时错误:"类型为' CoreContext的DbContext'无法汇集,因为它没有一个公共构造函数接受类型为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.c更新为新样式:

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。现在我将默认回到非Pooling的替代方案,但是利用这个功能会很好。

5 个答案:

答案 0 :(得分:12)

使用DbContext Pooling时,将保留派生的DbContext类中您自己的状态(例如私有字段)。这意味着您的服务的生命周期现在为singleton。这就是为什么你不应该在这里注入其他服务的原因。 但是可以通过这种方式查询所需的服务: 首先,我们应该使用UseInternalServiceProvider上的DbContextOptionsBuilder方法告诉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类使用以下方法

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

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

this是DbContext的当前实例。

答案 1 :(得分:2)

&#34;因为它没有一个公共构造函数接受DbContextOptions类型的单个参数&#34;

如果除了接受DbContextOptions的公共构造函数之外还有任何公共构造函数,则需要删除它们或将它们设置为非公共构造函数才能使用上下文池。

此外,通过覆盖OnConfiguring方法可以做什么也有限制。这在此处的文档中引用,但它没有明确说明这些限制是什么:https://docs.microsoft.com/en-us/ef/core/what-is-new/index#dbcontext-pooling

答案 2 :(得分:1)

当您“ Scaffold-Dbcontext”并生成两个构造函数时,通常会遇到此问题。

简单解决方案: 1. AddDbContextPool : 如果要使用AddDbContextPool,请删除空的构造函数,并使用DbContextOptionsBuilder进行维护。请注意,在这种情况下,您可能必须提供如先前文章中所建议的选项。

  1. AddDbContext : 使用AddDbContext,您可以同时拥有构造函数/重载

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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