EFCore无法识别数据库提供者 [英] EFCore Not recognizing Database Provider
问题描述
我有一个.Net Core WebApplication项目,其中上下文类位于类库中.如果我在OnConfiguring(DbContextOptionsBuilder optionsBuilder)方法中对连接字符串进行硬编码,则可以生成迁移.因为最好让依赖注入来管理上下文,所以我想将其添加到Startup Class中.但是,当我这样做时,会出现以下错误:
I have a .Net Core WebApplication Project in which the Context Class is in a Class Library. If I hard code the connection string in the OnConfiguring(DbContextOptionsBuilder optionsBuilder) method I can generate migrations. Since it is better to let dependency injection manage the context I would like to add this to the Startup Class. However when I do I get the following error:
尚未为此DbContext配置数据库提供程序.可以通过重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext来配置提供程序.如果使用AddDbContext,则还要确保您的DbContext类型在其构造函数中接受DbContextOptions对象,并将其传递给DbContext的基本构造函数.
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for 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();
}
推荐答案
这让我很难受,得到了如下错误:
This bit me hard, getting errors like:
-
No database provider has been configured for this DbContext.
-
No design-time services were found.
-
The server was not found or was not accessible.
No database provider has been configured for this DbContext.
No design-time services were found.
The server was not found or was not accessible.
但是我最终得到了一个相当简单的解决方案/解决方法:
But I ended up with a fairly simple solution/work-around:
- Set the default startup-project in your solution (or in your command line)
in your
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地址和端口号(受查询以获取IP ).
所以现在我的appsettings.Development.json
中有此内容:
in your connection-string use the IP-address and port-number (inspired by this corefx issue), instead of the server-name/dns (FWIW: query to get IP).
So now I have this in my appsettings.Development.json
:
"ConnectionStrings":{ "MyConnectionStringName":数据源= 10.1.2.3,1433;初始目录= MyCatalog;集成安全性= SSPI" }
"ConnectionStrings": { "MyConnectionStringName": "Data Source=10.1.2.3,1433; Initial Catalog=MyCatalog; Integrated Security=SSPI" }
我发现了很多其他建议,并且我还会提到一些看起来很有趣的建议.也许会帮助其他人:
I found a lot of other suggestions, and I will mention a few that seemed interesting. Maybe it will help someone else:
在命令行中提及启动项目和迁移项目
Mention startup-project and migration-project in command-line:
Update-Database -Verbose -Project x.Data -StartupProject x.Web
从代码迁移
也可以在启动 ,"用于具有本地数据库的应用程序". (我想否则会在多个节点上运行,是否可能同时出现并发问题而启动多个运行时迁移?)
Migrate from code
One can also call migrations at StartUp , "for apps with a local database". (I guess otherwise running on multiple nodes, may start multiple runtime migrations at the same time with concurrency issues?)
myDbContext.Database.Migrate();
在Main.cs中设置DbContext
问题在于,当EF调用
CreateWebHostBuilder
或BuildWebHost
无需运行Main
即可执行此操作. (这是故意的 因为EF需要建立模型并使用DbContext
启动应用程序.)这意味着当EF调用这些应用程序时 方法,静态IConfiguration
属性仍然为null,因为它 仅在Main
中设置.因此,您需要确保 当EF调用以下方法之一时,将设置/处理IConfiguration
;或者 使用IDesignTimeDbContextFactory
.
The problem is that when EF calls either
CreateWebHostBuilder
orBuildWebHost
it does so without runningMain
. (This is intentional because EF needs to build the model and use theDbContext
without starting the application.) This means that when EF invokes on of these methods the staticIConfiguration
property is still null--since it is only set inMain
. So, you'll need to either make sure thatIConfiguration
is set/handled when EF calls one of these methods, or useIDesignTimeDbContextFactory
.
This is not necessary for me, I guess because .Net Core 2 loads the configuration behind the scenes.
执行此操作的典型方法是在
IDesignTimeDbContextFactory
中读取文件,环境变量或类似内容.
The typical way to do this is to read a file, an environment variable, or similar inside
IDesignTimeDbContextFactory
.
对我来说这似乎太过分了.
This seems too much a hack to me.
Microsoft文档提到:
一些EF核心工具命令(例如,迁移 命令)要求在设计时创建派生的DbContext实例 时间以收集有关应用程序实体类型的详细信息 以及它们如何映射到数据库架构.
Some of the EF Core Tools commands (for example, the Migrations commands) require a derived DbContext instance to be created at design time in order to gather details about the application's entity types and how they map to a database schema.
他们提到了提供这种设计时DbContext的这些方法:
They mention these ways to provide this design time DbContext:
-
来自应用程序服务:对于作为启动项目的ASP.NET Core应用程序:
from application services: for an ASP.NET Core app as startup project:
工具尝试从应用程序的 服务提供者. [...]工具首先尝试获得服务 通过调用
Program.BuildWebHost()
[JP:或CreateWebHostBuilder
]并访问IWebHost.Services
财产.DbContext
本身及其中的任何依赖项 构造函数需要在应用程序的应用程序中注册为服务 服务提供者.这可以很容易地通过构造函数来实现 在DbContext
上,该实例采用DbContextOptions<TContext>
作为参数并使用AddDbContext<TContext>
方法.
The tools try to obtain the
DbContext
object from the application's service provider. [...] The tools first try to obtain the service provider by invokingProgram.BuildWebHost()
[JP: orCreateWebHostBuilder
] and accessing theIWebHost.Services
property. TheDbContext
itself and any dependencies in its constructor need to be registered as services in the application's service provider. This can be easily achieved by having a constructor on theDbContext
that takes an instance ofDbContextOptions<TContext>
as an argument and using theAddDbContext<TContext>
method.
使用没有参数的构造函数
Using a constructor with no parameters
如果无法从应用程序服务获得
DbContext
提供程序,这些工具会在内部查找派生的DbContext
类型 项目.然后,他们尝试使用带有以下内容的构造函数创建实例 没有参数.如果DbContext
,则可以是默认构造函数. 是使用OnConfiguring
方法配置的.
If the
DbContext
can't be obtained from the application service provider, the tools look for the derivedDbContext
type inside the project. Then they try to create an instance using a constructor with no parameters. This can be the default constructor if theDbContext
is configured using theOnConfiguring
method.
在设计时工厂
From a design-time factory
您还可以通过以下方式告诉工具如何创建
DbContext
实现IDesignTimeDbContextFactory<TContext>
接口:如果 在同一个目录中找到实现此接口的类 项目作为派生的DbContext或在应用程序的启动中 项目,这些工具会绕过创建DbContext
的其他方式 并使用设计时工厂.
You can also tell the tools how to create your
DbContext
by implementing theIDesignTimeDbContextFactory<TContext>
interface: If a class implementing this interface is found in either the same project as the derived DbContext or in the application's startup project, the tools bypass the other ways of creating theDbContext
and use the design-time factory.
这篇关于EFCore无法识别数据库提供者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!