设计时 DbContext 创建Design-time DbContext Creation

某些 EF Core 工具命令(例如,迁移命令)需要在设计时创建一个派生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最好按照类似的方式配置创建,使其在运行时配置In most cases, it is desirable that the DbContext thereby created is configured in a similar way to how it would be configured at run time.

工具可通过多种方式来创建DbContextThere are various ways the tools try to create the DbContext:

从应用程序服务From application services

如果启动项目使用ASP.NET Core Web 主机.Net Core 泛型主机,则这些工具将尝试从应用程序的服务提供程序获取 DbContext 对象。If your startup project uses the ASP.NET Core Web Host or .NET Core Generic Host, the tools try to obtain the DbContext object from the application's service provider.

工具首先尝试通过调用Program.CreateHostBuilder()、调用Build(),然后访问Services属性来获取服务提供程序。The tools first try to obtain the service provider by invoking Program.CreateHostBuilder(), calling Build(), then accessing the Services property.

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 class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

备注

创建新的 ASP.NET Core 应用程序时,默认情况下会包括此挂接。When you create a new ASP.NET Core application, this hook is included by default.

自身DbContext及其构造函数中的任何依赖项都需要在应用程序的服务提供程序中注册为服务。The DbContext itself and any dependencies in its constructor need to be registered as services in the application's service provider. 通过在DbContext实例DbContextOptions<TContext> 作为参数并使用方法的上,可以轻松实现这一点。AddDbContext<TContext> 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派生类型。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. DbContext 如果OnConfiguring使用方法配置,则这可能是默认构造函数。This can be the default constructor if the DbContext is configured using the OnConfiguring method.

从设计时工厂From a design-time factory

还可以通过实现IDesignTimeDbContextFactory<TContext>接口来告诉工具如何创建 DbContext:如果在与派生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 instead.

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

备注

当前args未使用该参数。The args parameter is currently unused. 跟踪从工具中指定设计时参数的功能时出现问题There is an issue tracking the ability to specify design-time arguments from the tools.

如果需要以不同于运行时的方式配置 DbContext 的设计时, DbContext则设计时工厂特别有用。如果构造函数采用其他参数,则不会在 di 中注册,如果根本不使用 di,或者对于某些原因:不BuildWebHost希望在 ASP.NET Core 应用程序的Main类中使用方法。A design-time factory can be especially useful if you need to configure the DbContext differently for design time than at run time, if the DbContext constructor takes additional parameters are not registered in DI, if you are not using DI at all, or if for some reason you prefer not to have a BuildWebHost method in your ASP.NET Core application's Main class.