EFCore 无法识别数据库提供程序
Posted
技术标签:
【中文标题】EFCore 无法识别数据库提供程序【英文标题】:EFCore Not recognizing Database Provider 【发布时间】:2017-10-28 12:24:52 【问题描述】:我有一个 .Net Core WebApplication 项目,其中上下文类位于类库中。如果我在 OnConfiguring(DbContextOptionsBuilder optionsBuilder) 方法中硬编码连接字符串,我可以生成迁移。由于最好让依赖注入管理上下文,因此我想将其添加到启动类中。但是,当我这样做时,会出现以下错误:
没有为此 DbContext 配置数据库提供程序。可以通过重写 DbContext.OnConfiguring 方法或在应用程序服务提供者上使用 AddDbContext 来配置提供者。如果使用了 AddDbContext,那么还要确保您的 DbContext 类型在其构造函数中接受 DbContextOptions 对象并将其传递给 DbContext 的基本构造函数。
DbContext 类:
public class CustomerManagerContext : IdentityDbContext<User, Role, long, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>
public CustomerManagerContext()
public CustomerManagerContext(DbContextOptions<CustomerManagerContext> options) : base(options)
//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//
// base.OnConfiguring(optionsBuilder);
// optionsBuilder.UseSqlServer("SecretConnectionString");
//
protected override void OnModelCreating(ModelBuilder builder)
base.OnModelCreating(builder);
builder.Entity<User>().ToTable("Users");
builder.Entity<Role>().ToTable("Roles");
builder.Entity<UserClaim>().ToTable("UserClaims");
builder.Entity<UserRole>().ToTable("UserRoles");
builder.Entity<UserLogin>().ToTable("UserLogins");
builder.Entity<RoleClaim>().ToTable("RoleClaims");
builder.Entity<UserToken>().ToTable("UserTokens");
启动类 - ConfigureServices 方法
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<CustomerManagerContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddEntityFrameworkSqlServer()
.AddDbContext<CustomerManagerContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<CustomerManagerContext>()
.AddDefaultTokenProviders();
【问题讨论】:
不完全确定,但对我来说,您同时使用AddDbContext
和AddEntityFrameworkSqlServer
听起来完全不正确(而且您在这里也调用UseSqlServer
)。尝试注释掉对AddEntityFrameworkSqlServer
的调用
@CamiloTerevinto 我已尝试将两者都注释掉,但都没有。奇怪的是,如果我使用 OnConfiguring 设置有效。我必须错过一些东西。
您也可以尝试删除两个构造函数,或者至少删除无参数的构造函数
@CamiloTerevinto 如果我删除两个构造函数,我会得到相同的错误。如果我只是删除无参数的,我会收到以下错误。在“CustomerManagerContext”上找不到无参数构造函数。将无参数构造函数添加到“CustomerManagerContext”或在与“CustomerManagerContext”相同的程序集中添加“IDbContextFactory.AddDbContext
和AddEntityFrameworkSqlServer
,只删除AddEntityFrameworkSqlServer
一个。我怀疑它是因为两者都注册了DbContextOptionsBuilder
的两个实例,并且当DI 尝试通过provider.GetRequiredService<T>()
解决它时,当有多个注册时它会失败。一个以上的注册只能通过GetRequiredServices
(复数)解决
【参考方案1】:
这让我很难受,出现如下错误:
No database provider has been configured for this DbContext.
No design-time services were found.
The server was not found or was not accessible.
但我最终得到了一个相当简单的解决方案/解决方法:
在您的解决方案(或命令行)中设置默认的startup-project
在你的Startup.cs
add the migration-project:
public void ConfigureServices(IServiceCollection services)
var myDbContextAssemblyName = typeof(MyDbContext).Assembly.GetName().Name;
var connectionString = Configuration.GetConnectionString(MyDbContext.ConnectionStringName);
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(
connectionString,
x => x.MigrationsAssembly(myDbContextAssemblyName)));
// do more ...
在您的连接字符串中使用 IP 地址和端口号(灵感来自 this corefx issue),而不是服务器名称/dns(FWIW:query to get IP)。
所以现在我在我的appsettings.Development.json
中有这个:
“连接字符串”: “MyConnectionStringName”:“数据源=10.1.2.3,1433;初始目录=MyCatalog;集成安全=SSPI”
TLDR:其他建议
我发现了很多其他的建议,我会提到一些看起来很有趣的。也许它会帮助别人:
命令行中的项目名称
在命令行中提及启动项目和迁移项目:
Update-Database -Verbose -Project x.Data -StartupProject x.Web
添加(来自 cmets):这也适用于 dotnet CLI:
dotnet ef migrations add <MIGRATION_NAME> --project <DATABASE_PROJECT_DIR> --startup-project <STARTUP_PROJECT_DIR> dotnet ef database update --project <DATABASE_PROJECT_DIR> --startup-project <STARTUP_PROJECT_DIR>
从代码迁移
也可以通过StartUp 致电迁移 , “适用于具有本地数据库的应用程序”。 (我猜想否则在多个节点上运行,可能会同时启动多个运行时迁移并出现并发问题?)
myDbContext.Database.Migrate();
在 Main.cs 中设置 DbContext
This EntityFrameworkCore issue 状态:
问题是当 EF 调用
CreateWebHostBuilder
或BuildWebHost
它在不运行Main
的情况下这样做。 (这是故意的 因为 EF 需要构建模型并使用DbContext
而不 启动应用程序。)这意味着当 EF 调用这些 方法静态IConfiguration
属性仍然为空——因为它 仅在Main
中设置。因此,您需要确保IConfiguration
在 EF 调用这些方法之一时设置/处理,或者 使用IDesignTimeDbContextFactory
。
这对我来说不是必需的,我猜是因为 .Net Core 2 loads the configuration behind the scenes。
将 IDesignTimeDbContextFactory 与环境变量一起使用
This EntityFrameworkCore issue 状态:
执行此操作的典型方法是读取文件、环境变量或
IDesignTimeDbContextFactory
中的类似内容。
这对我来说似乎太过分了。
在设计时创建 DbContext
Microsoft documentation 提及:
一些 EF Core Tools 命令(例如,迁移 命令)需要在设计时创建派生的 DbContext 实例 收集有关应用程序实体类型的详细信息的时间 以及它们如何映射到数据库架构。
他们提到了提供这种设计时 DbContext 的这些方法:
来自应用程序服务:对于作为启动项目的 ASP.NET Core 应用程序:使用不带参数的构造函数这些工具会尝试从应用程序的 服务提供者。 [...]工具首先尝试获取服务 通过调用
Program.BuildWebHost()
[JP: 或CreateWebHostBuilder
] 并访问IWebHost.Services
财产。DbContext
本身及其中的任何依赖项 构造函数需要注册为应用程序的服务 服务提供者。这可以通过构造函数轻松实现 在DbContext
上,它带有一个实例DbContextOptions<TContext>
作为参数并使用AddDbContext<TContext>
方法。
来自设计时工厂如果无法从应用服务获取
DbContext
提供者,这些工具会在 项目。然后他们尝试使用构造函数创建一个实例 没有参数。如果DbContext
这可以是默认构造函数 使用OnConfiguring
方法配置。
您还可以通过以下方式告诉工具如何创建您的
DbContext
实现IDesignTimeDbContextFactory<TContext>
接口:如果 实现此接口的类位于同一 项目作为派生的 DbContext 或在应用程序的启动中 项目,工具绕过创建DbContext
的其他方式 并使用设计时工厂。
【讨论】:
是的 IDesignTimeDbContextFactorycontext.Database.Migrate
发帖OnConfiguring
?我有一个动态的每租户配置,我希望在租户信息可用后生成数据库。也发布了here。
@Shimmy,这似乎更像是一个新的相关问题,而不是评论。然而,假设你有一个public class MyDbContext: DbContext
,你可以显式调用一个单独的方法,例如:new MyDbContext().MyMigrationMethod()
,其中新的(隐式)调用this.OnConfiguring
和MyMigrationMethod()
应该显式调用this.Database.Migrate()
。在您知道您的租户相关配置已知并将应用(例如从您的租户调用它)之后调用它,但在使用您的数据库之前,当然。
这也适用于 dotnet CLI:dotnet ef migrations add <MIGRATION_NAME> --project <DATABASE_PROJECT_DIR> --startup-project <STARTUP_PROJECT_DIR>
dotnet ef database update --project <DATABASE_PROJECT_DIR> --startup-project <STARTUP_PROJECT_DIR>
【参考方案2】:
当我在将 dbcontext 添加到以下服务时提供选项以及 dbcontext 时遇到了同样的问题:-
services.AddDbContext<TodoContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
然后我添加了没有如下选项的 dbcontext,它为我解决了问题
services.AddDbContext<TodoContext>();
我还必须向 dbcontext 类添加 OnConfiguring 方法,以便上下文可以访问连接字符串:-
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=IdenDB;Trusted_Connection=True;MultipleActiveResultSets=true");
我不确定这是否是正确的做事方式,因为我刚开始使用核心,但here 是一个更详细地解释了这个问题的答案
【讨论】:
以上是关于EFCore 无法识别数据库提供程序的主要内容,如果未能解决你的问题,请参考以下文章