在 Entity Framework Core 中创建迁移时如何配置 DbContext?

How do you configure the DbContext when creating Migrations in Entity Framework Core?

在使用Entity Framework的迁移命令时,有没有办法实现依赖注入configured/bootstrapped?

Entity Framework 核心支持 DbContext 子类的依赖注入。此机制包括允许配置 DbContext.

之外的数据访问

例如,以下内容会将 EF 配置为使用从 config.json

检索到的连接字符串持久保存到 SQL 服务器
ServiceCollection services = ...

var configuration = new Configuration().AddJsonFile( "config.json" );
services.AddEntityFramework( configuration )
    .AddSqlServer()
    .AddDbContext<BillingDbContext>( config => config.UseSqlServer() );

但是,迁移命令不知道执行此代码,因此 Add-Migration 将因缺少提供程序或连接字符串而失败。

迁移可以通过覆盖 DbContext 子类中的 OnConfiguring 来指定提供程序和配置字符串来工作,但是当其他地方需要不同的配置时,这会妨碍工作。最终让我的迁移命令和我的代码同时工作变得非常复杂。

注意:我的 DbContext 位于与使用它的入口点不同的程序集中,并且我的解决方案有多个启动项目。

我知道这是一个老问题,但我使用了 onConfiguring 方法,我没有遇到这个问题

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(Startup.Configuration.Get("Data:DefaultConnection:ConnectionString"));
}

作为@bricelam commented this functionality does not yet exist in Entity Framework 7. This missing functionality is tracked by GitHub issue aspnet/EntityFramework#639

与此同时,我发现更简单的解决方法是利用全局状态而不是麻烦地进行子类化。通常不是我的第一个设计选择,但它现在运行良好。

在 MyDbContext 中:

public static bool isMigration = true;

protected override void OnConfiguring( DbContextOptionsBuilder optionsBuilder )
{
    // TODO: This is messy, but needed for migrations.
    // See https://github.com/aspnet/EntityFramework/issues/639
    if ( isMigration )
    {
        optionsBuilder.UseSqlServer( "<Your Connection String Here>" );
    }
}

Startup.ConfigureServices().

public IServiceProvider ConfigureServices( IServiceCollection services )
{
    MyContext.isMigration = false;

    var configuration = new Configuration().AddJsonFile( "config.json" );
    services.AddEntityFramework( configuration )
        .AddSqlServer()
        .AddDbContext<MyDbContext>( config => config.UseSqlServer() );
    // ...
}

(在我的例子中,配置代码实际上存在于 Autofac 模块中。)

我只是在我的 Startup.cs 文件中请求实例和 运行 迁移

  public void ConfigureServices(IServiceCollection services)
    {
        // ASPNet Core Identity
        services.AddDbContext<RRIdentityDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("RRIdentityConnectionString")));

     }

然后在配置中:

   public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        var rrIdentityContext = app.ApplicationServices.GetService<RRIdentityDbContext>();
        rrIdentityContext.Database.Migrate();
    }

注意:数据库没有'EnsureCreated'。如果它不存在,Migrate 应该会创建它,尽管我不知道它应该如何计算权限 - 所以我创建了一个空数据库。

结合上面的答案,这对我有用

private readonly bool isMigration = false;
public MyContext()
{
    isMigration = true;
}

public MyContext(DbContextOptions<MyContext> options) : base(options)
{

}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (isMigration)
    {
        optionsBuilder.UseSqlServer("CONNECTION_STRING");
    }
}

使用IDesignTimeDbContextFactory

如果在与派生 DbContext 相同的项目中或在应用程序的启动项目中发现实现此接口的 class,则工具会绕过其他创建 [=12= 的方法] 并改用设计时工厂。

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace MyProject
{
    public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
    {
        public BloggingContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
            optionsBuilder.UseSqlite("Data Source=blog.db");

            return new BloggingContext(optionsBuilder.Options);
        }
    }
}

应用于 Entity Framework 2.0、2.1


使用 IDbContextFactory<TContext> 现在是 obsolete.

实现此接口可为没有 public 默认构造函数的上下文类型启用设计时服务。设计时服务将自动发现与派生上下文位于同一程序集中的此接口的实现。

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace MyProject
{
    public class BloggingContextFactory : IDbContextFactory<BloggingContext>
    {
        public BloggingContext Create()
        {
            var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
            optionsBuilder.UseSqlServer("connection_string");

            return new BloggingContext(optionsBuilder.Options);
        }
    }
}

更多信息:https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext

如果您对硬编码的连接字符串不满意,请查看 this 文章。

在 .NET Core 中,应使用 2.1 版IDesignTimeDbContextFactory,因为 IDbContextFactory 已过时。

public class FooDbContextFactory : IDesignTimeDbContextFactory<FooDbContext>
{
    public FooDbContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

        var builder = new DbContextOptionsBuilder<FooDbContext>();
        var connectionString = configuration.GetConnectionString("ConnectionStringName");
        builder.UseSqlServer(connectionString);

        return new FooDbContext(builder.Options);
    }
}

如果您正在寻找为迁移配置上下文的解决方案,您可以在 DBContext class:

中使用它
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();
            var connectionString = configuration.GetConnectionString("DbCoreConnectionString");
            optionsBuilder.UseSqlServer(connectionString);
        }
    }

记得安装这两个包以具有 SetBasePathAddJsonFile 方法: Microsoft.Extensions.Configuration.FileExtensions

Microsoft.Extensions.Configuration.Json