設計階段 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() ,然後存取屬性來嘗試取得服務提供者 ServicesThe 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. 只要將的函 DbContextDbContextOptions<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 OnConfiguringThis can be the default constructor if the DbContext is configured using the OnConfiguring method.

從設計階段工廠From a design-time factory

您也可以藉由執行介面,告訴工具如何建立您的 DbCoNtext IDesignTimeDbContextFactory<TContext> :如果在相同的專案中找到實作為此介面的類別 DbContext ,或在應用程式的啟始專案中找到這個介面,則工具會略過其他建立 DbCoNtext 的方法,並改為使用設計階段 factory。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);
        }
    }
}

注意

在 EFCore 5.0 之前, args 參數未使用 () 會看到 此問題Prior to EFCore 5.0 the args parameter was unused (see this issue). 這在 EFCore 5.0 中已修正,而且任何額外的設計階段引數都會透過該參數傳遞至應用程式。This is fixed in EFCore 5.0 and any additional design-time arguments are passed into the application through that parameter.

如果您需要以不同于執行時間的方式來設定設計階段的 DbCoNtext,則設計階段處理站會特別有用,如果函式 DbContext 接受其他參數,則不會在 di 中註冊,如果您根本不使用 di,或基於某些原因,您不想 BuildWebHost 在 ASP.NET Core 應用程式的類別中有方法 MainA 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.