Entity Framework 迁移:总是调用配置的构造函数

Entity Framework Migrations: Constructor of Configuration called always

我创建了一个简单的控制台应用程序,从 nuget 安装 EntityFramework 并执行命令 Enable-Migrations。

这里是main的代码:

using(var ctx = new AppDbContext())
{
   var persons = ctx.Persons.ToList();
   Console.ReadKey();
}

这里是class配置的代码

internal sealed class Configuration : DbMigrationsConfiguration<AppDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        Console.WriteLine("Configuration: Constructor");
    }

    protected override void Seed(AppDbContext context)
    {
        Console.WriteLine("Configuration: Seed");
    }
}

这是 app.config 中的 entity framework 部分:

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="mssqllocaldb" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
</entityFramework>

如果我 运行 控制台应用程序,则执行迁移的配置 class 的构造函数。为什么?我不更改数据库初始化程序。

Update

我现在尝试了一些数据库初始化程序并查看是否调用了 Configuration class 构造函数。这是我的结果:

public class AppDbContext : DbContext
{
    static AppDbContext()
    {
        //Database.SetInitializer<AppDbContext>(new CreateDatabaseIfNotExists<AppDbContext>());
        // ==> Configuration class constructor called

        //Database.SetInitializer<AppDbContext>(new DropCreateDatabaseIfModelChanges<AppDbContext>());
        // ==> Configuration class constructor called

        //Database.SetInitializer<AppDbContext>(new DropCreateDatabaseAlways<AppDbContext>());
        // ==> Configuration class constructor called

        Database.SetInitializer<AppDbContext>(null);
        // ==> Configuration class constructor is NOT called
    }

    public IDbSet<Person> Persons { get; set; }
}

我显式设置了数据库初始值设定项,但调用了 Configuration class 构造函数。奇怪的行为。

正如您提到的,您已经执行了命令 Enable-Migrations。那么是做什么的,添加一个新的迁移配置 class。当您 运行 您的应用程序时,此 class 将应用在 class 中指定的与迁移相关的配置更改。

DatabaseInitializers 是应用迁移的策略,即使您没有触及它们,Configuration class 的对象也会被实例化。

Update:

如果您没有在代码中执行此操作,请查看您的应用程序配置文件。那可能看起来像:

    <contexts>
      <context type="AppDbContext, MyAssembly">
        <databaseInitializer 
type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[AppDbContext, MyAssembly], 
                             [Migrations.Configuration, MyAssembly]], EntityFramework" />  


</context>

有关详细信息,请参阅此 documentation

Update 2:

我想我找到了答案。当查看 EntityFramework 代码时,可以清楚地看到当您的第一个 linq 查询实现时,databaseInitializer 被触发。查看下面在调试您的应用程序时捕获的调用堆栈。

案例 1: 当您使用 Database.SetInitializer<AppDbContext>(null); 时,它实际上创建了一个 NullDatabaseInitializer<TContext>() 作为默认初始化程序,它什么都不做,因此不会调用配置。

案例 2: 当您删除行 Database.SetInitializer<AppDbContext>(null); 时,事情开始使用提供程序的默认值。在这种情况下,没有提供 DatabaseInitializer 的外部规范,因此 EF 将获得默认的 Initializer,在这种情况下为 CreateIfNotExist<AppDbContext>。 然后初始化程序将尝试找到配置,当然它有一个配置 class 所以,配置 class 将被实例化并调用构造函数。

尽管我花了几个小时才弄明白。