问题描述
我正在尝试将当前的.Net Core应用程序从1.1升级到2.0,并收到此运行时错误:无法合并类型为'CoreContext'的DbContext,因为它没有单个公共构造函数来接受单个参数键入DbContextOptions".
I am trying to upgrade our current .Net Core application from 1.1 to 2.0 and am getting this runtime error: "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<>时,它仍然有效.
It is caused by using the new IServiceCollection.AddDbContextPool<> function. When I use IServiceCollection.AddDbContext<> it still works.
此应用程序是DB-First,因此我使用'Scaffold-DbContext'生成了所有上下文.因此,出于注入其他服务的需要,我在每个上下文中都有一个扩展,如下所示:
This application is DB-First, so I generate all our contexts using 'Scaffold-DbContext'. Due to that, and the need to inject other services I have an extension on every context like this:
public partial class CoreContext
{
public CoreContext(
DbContextOptions<CoreContext> options,
IUserService userService,
IAuditRepository auditRepository
) : base(options) {...}
}
每当我运行Scaffold-DbContext时,我都会从CoreContext中删除自动生成的构造方法,但是即使将其放在其中,我仍然会收到此错误.
Whenever I run the Scaffold-DbContext I just remove the autogenerated Constructor from CoreContext, but even if I put it in there I still get this error.
public partial class CoreContext : DbContext
{
public CoreContext(DbContextOptions<CoreContext> options) : base(options) {}
}
我已经将Program.cs更新为新样式:
I've already updated Program.cs to the new style:
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非常简单:
And the Startup.cs is pretty straightforward:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
services.AddDbContextPool<CoreContext>(options => options.UseSqlServer(absConnectionString));
...
}
如果有帮助,我正在将Autofac用于DI.现在,我将默认使用非池化选项,但是最好利用此功能.
I am using Autofac for DI if that helps. For now I'll default back to the non-Pooling alternative, but it would be nice to take advantage of this feature.
推荐答案
使用DbContext Pooling
时,将保留派生DbContext类中您自己的状态(例如私有字段).这意味着您的服务寿命现在为singleton
.这就是为什么您不应该在这里拥有其他注入服务的原因.但是可以通过这种方式查询所需的服务:首先,我们应该在DbContextOptionsBuilder
上使用UseInternalServiceProvider
方法来告诉EF哪个服务提供者使用其服务.该服务提供者必须具有为EF和任何提供者配置的所有服务.因此,我们应该手动注册EF服务:
When using DbContext Pooling
, your own state (e.g. private fields) in your derived DbContext class will be preserved. Which means the lifetime of your services is now singleton
. That's why you shouldn't have other injected services here. But it's possible to query the required services this way:First we should use the UseInternalServiceProvider
method on DbContextOptionsBuilder
to tell EF which service provider to use for its services. This service provider must have all the services configured for EF and any providers. So we should register EF Services manually:
services.AddEntityFrameworkSqlServer();
然后介绍应用程序的服务提供商,该服务提供商现在也包括EF Services:
And then introduce the application's services provider which now includes the EF Services too:
services.AddDbContextPool<ApplicationDbContext>((serviceProvider, optionsBuilder) =>
{
optionsBuilder.UseSqlServer("...");
optionsBuilder.UseInternalServiceProvider(serviceProvider);
});
之后,定义以下名称空间:
After that define these namespaces:
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
现在,您可以在使用以下方法的ApplicationDbContext类
And now you can access the registered services in the application within the ApplicationDbContext class using the following methods
var siteSettings = this.GetService<IOptionsSnapshot<SiteSettings>>();
或
var siteSettings = this.GetInfrastructure().GetRequiredService<IOptionsSnapshot<SiteSettings>>();
this
是DbContext的当前实例.
this
is the current instance of the DbContext.
这篇关于无法合并类型为DbContext的DbContext,因为它没有单个公共构造函数接受单个类型为DbContextOptions的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!