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

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

问题描述

我有一个.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:

  • 在解决方案(或命令行)中设置默认的启动项目
  • 您的Startup.cs中的
  • 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

    此EntityFrameworkCore问题指出:

    问题在于,当EF调用CreateWebHostBuilderBuildWebHost无需运行Main即可执行此操作. (这是故意的 因为EF需要建立模型并使用DbContext 启动应用程序.)这意味着当EF调用这些应用程序时 方法,静态IConfiguration属性仍然为null,因为它 仅在Main中设置.因此,您需要确保 当EF调用以下方法之一时,将设置/处理IConfiguration;或者 使用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.

    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 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.

  • 使用没有参数的构造函数

  • 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 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.

  • 在设计时工厂

  • From a design-time factory

    您还可以通过以下方式告诉工具如何创​​建DbContext 实现IDesignTimeDbContextFactory<TContext>接口:如果 在同一个目录中找到实现此接口的类 项目作为派生的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天全站免登陆