简体   繁体   中英

EF Core 2.1 - No database provider has been configured for this DbContext

I have ASP.Net Core 2.1 with EF Core 2.1. This is how my DbContext class looks like

app.DAL.EF -> Layer

using app.domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;

namespace app.EF
{
 public class MyAppContext : DbContext
 {
    public MyAppContext(DbContextOptions<MyAppContext> options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new CustomerConfiguration());
        modelBuilder.HasDefaultSchema("app");
        base.OnModelCreating(modelBuilder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
    }

    public DbSet<Customer> Customers { get; set; }
 }

   public class MyAppContextConfiguration : IDesignTimeDbContextFactory<MyAppContext>
   {
    public MyAppContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
                                            .SetBasePath(Directory.GetCurrentDirectory())
                                            .AddJsonFile("appsettings.json", optional: false, true)
                                            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT ") ?? "Production" }.json", optional: true)
                                            .Build();

        var optionsBuilder = new DbContextOptionsBuilder<MyAppContext>();
        //optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        var dbConString = configuration.GetConnectionString("ITMDbConnection");

        optionsBuilder.UseSqlServer(dbConString);

        return new MyAppContext(optionsBuilder.Options);
    }
}

public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        builder.HasKey(x => x.Id);
    }
}}

app.DI -> Layer

  public static class Factory
  {
    public static void Initialize(ref IServiceCollection services)
    {
        //services.AddTransient<MyAppContext>();
        services.AddDbContext<MyAppContext>(options =>
        {

        });
        //services.AddTransient<MyAppContextConfiguration>();
        services.AddTransient<ICustomerRepository, CustomerRepository>();
    }
}

app.API -> Layer

 namespace app.api
 {
 public class Startup
 {
     public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        Factory.Initialize(ref services);
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}}

When running Add-Migration DbInit from Package Manager Console, throwing the below error

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.

错误

Thanks!

it is easactly what it says - there is no database provider attached.

Look at all your code. Where do you specify the database provider? Something like UseSqlServer (in OnConfiguring of the DbContext), depending on what database provider you want to use.

Inside ConfigureServices

services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(
        Configuration.GetConnectionString("DefaultConnection")));

In appsettings.json

{
    "ConnectionStrings": {
        "DefaultConnection": "SQL connection string"
    }
}

The error is clear - the provider and connection are never configured. All this code could be replaced with this context :

public class MyAppContext : DbContext
 {
    public DbSet<Customer> Customers { get; set; }

    public MyAppContext(){}

    public MyAppContext(DbContextOptions<MyAppContext> options)
        :base(options)
    {}

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //The base method is empty
        modelBuilder.HasDefaultSchema("app");
    }
 }

And a call to AddDbContext inside ConfigureServices :


 public class Startup
 {
     public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyAppContext>(options =>
        {
            var dbConString = Configuration.GetConnectionString("ITMDbConnection");
            options.UseSqlServer(dbConString);
        });


        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    ....

}

Most applications have more than one DbContext though. One option would be to add another method to Startup.cs to register them. For more complex applications, eg applications composed of different domains/modules/subsystems/projects, a better idea would be to create extension methods, eg :

public static CustomerDomainExtensions
{
    public static IServicesCollection AddCustomerDomain(this IServicesCollection services,IConfiguration configuration)
    {
        return services.AddCustomerContexts(configuration)
                       .AddRepositories(...)
                       ...;

    }

    public static AddCustomerContexts(this IServicesCollection services,IConfiguration configuration)
    {
        var dbConString = Configuration.GetConnectionString("ITMDbConnection");
        services.AddDbContext<MyAppContext>(options =>
        {
            options.UseSqlServer(dbConString);
        });
        //Add more contexts ...
    }
}

In Startup.cs , this would be called inside ConfigureServices . This is how all Microsoft.Extensions.* classes work, by providing Add and Use extension methods for use in Startup.cs :

public void ConfigureServices(IServiceCollection services)
{
    services.AddCustomerDomain(Configuration);


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

EDIT

Added a default constructor to the DbContext

I had the same issue.

You need to add base(options) to your constructor.

    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }

This will pass trough the options parameter to the base constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM