设计时 DbContext 创建

某些 EF Core Tools 命令(例如 Migrations 命令)要求在设计时创建派生的 DbContext 实例,以便收集有关应用程序实体类型及其如何映射到数据库架构的详细信息。 在大多数情况下,由此创建的 DbContext 的配置方式最好与其在运行时的配置方式类似。

这些工具试图以多种方式创建 DbContext

从应用程序服务

如果启动项目使用 ASP.NET Core Web 主机.NET Core 泛型主机,则这些工具将尝试从应用程序的服务提供程序获取 DbContext 对象。

这些工具首先尝试通过调用 Program.CreateHostBuilder()、调用 Build(),然后访问 Services 属性来获取服务提供程序。

public class Program
{
    public static void Main(string[] args)
        => CreateHostBuilder(args).Build().Run();

    // EF Core uses this method at design time to access the DbContext
    public static IHostBuilder CreateHostBuilder(string[] args)
        => Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder => webBuilder.UseStartup<Startup>());
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
        => services.AddDbContext<ApplicationDbContext>();

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    }
}

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

注意

创建新的 ASP.NET Core 应用程序时,默认包括此挂钩。

DbContext 本身及其构造函数中的任何依赖项都需要在应用程序的服务提供程序中注册为服务。 这可以通过DbContext 上有一个以 DbContextOptions<TContext> 的实例为参数的构造函数,并使用 AddDbContext<TContext> 方法来轻松实现。

使用不带参数的构造函数

如果无法从应用程序服务提供程序获得 DbContext,则这些工具将查找项目中的派生 DbContext 类型。 然后,它们尝试使用不带参数的构造函数创建实例。 如果 DbContext 是使用 OnConfiguring 方法配置的,则这可以是默认构造函数。

从设计时工厂

还可以通过实现 Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory<TContext> 接口来告知工具如何创建 DbContext:如果在与派生的 DbContext 相同的项目中或在应用程序的启动项目中找到实现此接口的类,则这些工具会绕过创建 DbContext 的其他方式,转而使用设计时工厂。

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

如果需要在设计时以不同于运行时的方式配置 DbContext,如果 DbContext 构造函数采用未在 DI 中注册的附加参数,如果你根本不使用 DI,或者如果你出于某种原因不希望在 ASP.NET Core 应用程序的 Main 类中使用 CreateHostBuilder 方法,则设计时工厂可能特别有用。

Args

IDesignTimeDbContextFactory<TContext>.CreateDbContextProgram.CreateHostBuilder 都接受命令行参数。

可通过这些工具指定以下参数:

dotnet ef database update -- --environment Production

-- 标记指示 dotnet ef 将后面的所有内容都视为参数,而不要试图将它们解析为选项。 dotnet ef 未使用的任何额外参数都会转发到应用。