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();

【问题讨论】:

不完全确定,但对我来说,您同时使用AddDbContextAddEntityFrameworkSqlServer 听起来完全不正确(而且您在这里也调用UseSqlServer)。尝试注释掉对AddEntityFrameworkSqlServer的调用 @CamiloTerevinto 我已尝试将两者都注释掉,但都没有。奇怪的是,如果我使用 OnConfiguring 设置有效。我必须错过一些东西。 您也可以尝试删除两个构造函数,或者至少删除无参数的构造函数 @CamiloTerevinto 如果我删除两个构造函数,我会得到相同的错误。如果我只是删除无参数的,我会收到以下错误。在“CustomerManagerContext”上找不到无参数构造函数。将无参数构造函数添加到“CustomerManagerContext”或在与“CustomerManagerContext”相同的程序集中添加“IDbContextFactory”的实现。 PM> add-migration Initial @Dblock247:您不应该同时删除.AddDbContextAddEntityFrameworkSqlServer,只删除AddEntityFrameworkSqlServer 一个。我怀疑它是因为两者都注册了DbContextOptionsBuilder 的两个实例,并且当DI 尝试通过provider.GetRequiredService&lt;T&gt;() 解决它时,当有多个注册时它会失败。一个以上的注册只能通过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 调用 CreateWebHostBuilderBuildWebHost 它在不运行 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&lt;TContext&gt; 作为参数并使用 AddDbContext&lt;TContext&gt; 方法。

使用不带参数的构造函数

如果无法从应用服务获取DbContext 提供者,这些工具会在 项目。然后他们尝试使用构造函数创建一个实例 没有参数。如果 DbContext 这可以是默认构造函数 使用OnConfiguring 方法配置。

来自设计时工厂

您还可以通过以下方式告诉工具如何创​​建您的DbContext 实现IDesignTimeDbContextFactory&lt;TContext&gt; 接口:如果 实现此接口的类位于同一 项目作为派生的 DbContext 或在应用程序的启动中 项目,工具绕过创建DbContext的其他方式 并使用设计时工厂。

【讨论】:

是的 IDesignTimeDbContextFactory 对我来说也是这个修复。谢谢,我忘了把我的解决方案放进去。 感谢您的详细解答。我怎样才能打电话给context.Database.Migrate 发帖OnConfiguring?我有一个动态的每租户配置,我希望在租户信息可用后生成数据库。也发布了here。 @Shimmy,这似乎更像是一个新的相关问题,而不是评论。然而,假设你有一个public class MyDbContext: DbContext,你可以显式调用一个单独的方法,例如:new MyDbContext().MyMigrationMethod(),其中新的(隐式)调用this.OnConfiguringMyMigrationMethod() 应该显式调用this.Database.Migrate()。在您知道您的租户相关配置已知并将应用(例如从您的租户调用它)之后调用它,但在使用您的数据库之前,当然。 这也适用于 dotnet CLI:dotnet ef migrations add &lt;MIGRATION_NAME&gt; --project &lt;DATABASE_PROJECT_DIR&gt; --startup-project &lt;STARTUP_PROJECT_DIR&gt; dotnet ef database update --project &lt;DATABASE_PROJECT_DIR&gt; --startup-project &lt;STARTUP_PROJECT_DIR&gt;【参考方案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 无法识别数据库提供程序的主要内容,如果未能解决你的问题,请参考以下文章

ThenInclude 在 EF Core 查询中无法识别

c++程序中,无法识别中文路径怎么办

带有 Gatsby 的 Redux - 无法识别包装的提供程序

Firebase 为发布请求提供“路径无法识别”错误

应用程序无法识别非 android jar 中的功能

Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务