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 将被实例化并调用构造函数。
尽管我花了几个小时才弄明白。
我创建了一个简单的控制台应用程序,从 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 将被实例化并调用构造函数。
尽管我花了几个小时才弄明白。