EFCore 无法识别数据库提供程序 [英] EFCore Not recognizing Database Provider

查看:17
本文介绍了EFCore 无法识别数据库提供程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 .Net Core WebApplication 项目,其中 Context 类位于类库中.如果我在 OnConfiguring(DbContextOptionsBuilder optionsBuilder) 方法中硬编码连接字符串,我可以生成迁移.由于最好让依赖注入管理上下文,因此我想将其添加到启动类中.但是,当我这样做时,我收到以下错误:

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:

  • 没有为此 DbContext 配置数据库提供程序.
  • 未找到设计时服务.
  • 未找到或无法访问服务器.

但我最终得到了一个相当简单的解决方案/变通方法:

But I ended up with a fairly simple solution/work-around:

  • 在您的解决方案(或命令行)中设置默认的startup-project

在您的 Startup.cs 添加迁移项目:

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 地址和端口号(灵感来自 这个 corefx 问题),而不是服务器名称/dns(FWIW:查询获取 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:

    连接字符串":{MyConnectionStringName":数据源=10.1.2.3,1433;初始目录=我的目录;集成安全=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
    

    添加(来自评论):这也适用于 dotnet CLI:

    Addition (from the comments): This also works from the 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> 
    

    从代码迁移

    还可以在 启动,对于具有本地数据库的应用".(我想否则会在多个节点上运行,可能会同时启动多个运行时迁移并出现并发问题?)

    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

    这个 EntityFrameworkCore 问题说明:

    问题是当 EF 调用 CreateWebHostBuilderBuildWebHost 它不需要运行 Main.(这是故意的因为 EF 需要构建模型并使用 DbContext 而没有启动应用程序.)这意味着当 EF 调用这些方法静态 IConfiguration 属性仍然为空——因为它仅在 Main 中设置.因此,您需要确保IConfiguration 在 EF 调用这些方法之一时设置/处理,或使用 IDesignTimeDbContextFactory.

    The problem is that when EF calls either CreateWebHostBuilder or BuildWebHost it does so without running Main. (This is intentional because EF needs to build the model and use the DbContext without starting the application.) This means that when EF invokes on of these methods the static IConfiguration property is still null--since it is only set in Main. So, you'll need to either make sure that IConfiguration is set/handled when EF calls one of these methods, or use IDesignTimeDbContextFactory.

    这对我来说不是必需的,我猜是因为 .Net Core 2 在后台加载配置.

    This is not necessary for me, I guess because .Net Core 2 loads the configuration behind the scenes.

    这个EntityFrameworkCore问题说明:

    执行此操作的典型方法是在 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.

    微软文档提到:

    某些 EF Core 工具命令(例如,Migrations命令)需要在设计时创建派生的 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 应用程序:

    这些工具尝试从应用程序中获取 DbContext 对象服务提供者.[...] 工具首先尝试获取服务通过调用 Program.BuildWebHost() [JP: 或CreateWebHostBuilder] 并访问 IWebHost.Services财产.DbContext 本身及其中的任何依赖项构造函数需要在应用程序中注册为服务服务提供者.这可以通过构造函数轻松实现在采用实例的 DbContextDbContextOptions 作为参数并使用AddDbContext 方法.

    The tools try to obtain the DbContext object from the application's service provider. [...] The tools first try to obtain the service provider by invoking Program.BuildWebHost() [JP: or CreateWebHostBuilder] and accessing the IWebHost.Services property. The DbContext 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 the DbContext that takes an instance of DbContextOptions<TContext> as an argument and using the AddDbContext<TContext> method.

    • 使用不带参数的构造函数
    • 如果DbContext无法从应用服务中获取提供者,这些工具在内部寻找派生的 DbContext 类型项目.然后他们尝试使用构造函数创建一个实例没有参数.如果 DbContext使用 OnConfiguring 方法进行配置.

      If the DbContext can't be obtained from the application service provider, the tools look for the derived DbContext type inside the project. Then they try to create an instance using a constructor with no parameters. This can be the default constructor if the DbContext is configured using the OnConfiguring method.

      • 来自设计时工厂
      • 您还可以通过以下方式告诉工具如何创​​建您的 DbContext实现 IDesignTimeDbContextFactory 接口:如果实现此接口的类可以在相同的项目作为派生的 DbContext 或在应用程序的启动项目,这些工具绕过了创建 DbContext 的其他方式并使用设计时工厂.

        You can also tell the tools how to create your DbContext by implementing the IDesignTimeDbContextFactory<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 the DbContext and use the design-time factory.

        这篇关于EFCore 无法识别数据库提供程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆