【问题标题】:EFCore Not recognizing Database ProviderEFCore 无法识别数据库提供程序
【发布时间】: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(复数)解决

标签: c# asp.net-core entity-framework-core entity-framework-migrations


【解决方案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 是一个更详细地解释了这个问题的答案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多