16

Is there way that dependency injection can be configured/bootstrapped when using Entity Framework's migration commands?

Entity Framework Core supports dependency injection for DbContext subclasses. This mechanism includes allowing for configuration of data access outside of of the DbContext.

For example, the following would configure EF to persist to a SQL server using a connection string retrieved from config.json

ServiceCollection services = ...

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

However, the migrations commands do not know to execute this code so Add-Migration will fail for lack of a provider or lack of a connection string.

Migrations can be made to work by overriding OnConfiguring within the DbContext subclass to specify the provider and configuration string, but that gets in the way when different configuration is desired elsewhere. Ultimately keeping my the migration commands and my code both working becomes undesirably complex.

Note: My DbContext lives in a different assembly than the entry point that uses it and my solution has multiple start-up projects.

4

7 回答 7

14

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

    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

于 2019-12-12T14:00:13.533 回答
6

正如@bricelam评论的那样,Entity Framework 7 中尚不存在此功能。GitHub 问题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 模块中。)

于 2015-06-28T17:58:11.683 回答
5

使用IDesignTimeDbContextFactory

如果在与派生项目相同的项目中DbContext或在应用程序的启动项目中找到实现此接口的类,则这些工具会绕过创建该接口的其他方法DbContext并改为使用设计时工厂。

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);
        }
    }
}

应用于实体框架 2.0、2.1


使用IDbContextFactory<TContext> 现在已过时

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

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

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

于 2017-05-25T11:38:18.657 回答
4

在 .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);
    }
}
于 2019-01-29T19:13:08.867 回答
2

结合上面的答案对我有用

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");
    }
}
于 2017-03-10T12:55:57.077 回答
1

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

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(Startup.Configuration.Get("Data:DefaultConnection:ConnectionString"));
}
于 2015-06-27T23:28:23.510 回答
0

我只是要求一个实例并在我的 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 应该创建它,尽管它应该如何找出我不知道的权限 - 所以我创建了一个空数据库。

于 2016-11-28T19:31:20.823 回答