我已经启动了一个EF6项目来存储分析仪器的测量结果。每台仪器都有一台内置的PC,并且有自己的结果数据库。
最初,使用了数据库初始化程序CreateDatabaseIfNotExists。在数据库创建时,它在__MigrationHistory表中创建一个条目,其中包含一个非唯一的MigrationId条目(时间戳因仪器而异,例如201706011336597_InitialCreate),如果是我的派生DbContext的完全限定类型,则为ContextKey。
过了一段时间,决定将更多结果数据添加到数据库中...幸运的是,只需要三个新表。现有表格没有变化。
为此,我想使用MigrateDatabaseToLatestVersion初始化程序。但我必须支持以下两种情况:
我该怎么做?
我使用初始DbContext中的add-migration PM控制台命令创建了初始迁移。这适用于方案2(不存在数据库)。从那个起点开始,我可以更新我的DbContext并使用三个新表创建一个新的迁移。
但如何支持方案1?初始迁移的Up()方法包含表创建代码,这不是必需的,因为表已经存在。空迁移(add-migration -IgnoreChanges)是否有用,可能使用比初始迁移更晚的时间戳?
注意:我无法从PM控制台访问目标数据库,只能在我的开发人员计算机上访问测试数据库。
谢谢和最好的问候
卡斯滕
更新 我已使用静态标志 TablesAlreadyCreated 修改了创建的初始迁移。
public partial class InitialMigraCreate : DbMigration
{
/// <summary>
/// Set this field to true, if the tables are already created by the
/// CreateDatabaseIfNotExists database initializer. Then, the Up()
/// and Down() methods do nothing, but the
/// migration is added to the __MigrationHistory table.
/// </summary>
public static bool TablesAlreadyCreated = false;
public override void Up()
{
if (TablesAlreadyCreated)
return;
// several CreateTable calls here
}
/// <inheritdoc/>
public override void Down()
{
if (TablesAlreadyCreated)
return;
// several Drop... calls here
}
}
我还实现了一个新的数据库初始化类,如下所示:
public class MigrateDatabaseToLatestVersionEx<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext>
where TContext : DbContext
where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
...
/// <inheritdoc />
public virtual void InitializeDatabase(TContext context)
{
if (context == null)
throw new ArgumentNullException("context");
// check whether a first migration exists from the CreateDatabaseIfNotExists database initializer
var firstConfig = new ConfigurationAutoCreatedDatabase();
firstConfig.TargetDatabase = _config.TargetDatabase;
var firstMigrator = new DbMigrator(firstConfig);
var firstDbMigrations = firstMigrator.GetDatabaseMigrations();
// create the default migrator with the current configuration
var migrator = new DbMigrator(_config);
if (1 == firstDbMigrations.Count(migra => migra.EndsWith("_InitialCreate", StringComparison.InvariantCultureIgnoreCase)))
{ // This database was created using the CreateDatabaseIfNotExists database initializer.
// That's an indication whether it's an old database
// Do the custom migration here!
InitialMigraCreate.TablesAlreadyCreated = true;
migrator.Update();
}
else
{ // do the default migration the database was created with this MigrateDatabaseToLatestVersionEx initializer
InitialMigraCreate.TablesAlreadyCreated = false;
migrator.Update();
}
}
}
它检查初始迁移条目是否来自 CreateDatabaseIfNotExists 初始化程序,并在该情况下禁用Up()/ Down()方法中的表创建/删除调用。 ConfigurationAutoCreatedDatabase 是手动创建的派生DbMigrationsConfiguration类:
internal sealed class ConfigurationAutoCreatedDatabase : DbMigrationsConfiguration<MyNamespace.MyDbContext>
{
/// <summary>
/// Creates a <c>ConfigurationAutoCreated</c> object (default constructor).
/// </summary>
public ConfigurationAutoCreatedDatabase()
{
this.AutomaticMigrationsEnabled = false;
this.AutomaticMigrationDataLossAllowed = false;
this.ContextKey = "MyNamespace.MyDbContext";
}
}
因此,它适用于两种情况。我希望能帮助其他有类似问题的人。如果该任务有一个开箱即用的EF工作流程,那将会很有趣。
答案 0 :(得分:0)
这是一个很常见的EF处理方式。非迁移初始值设定项(CreateDatabaseIfNotExists等)应该在很早的开发中使用(当你不关心数据时除了播种的东西)。
切换到迁移后,您应该生成一个基线迁移,在您指示时(add-migration MyStartPoint -IgnoreChanges
)获取当前模型的快照。这会添加一个没有Up()代码的迁移,并存储代码第一个模型的当前状态,这样当您更改模型时,只会反映这些更改。你可以通过注释掉Up()代码中存在的项来完成同样的事情。
现在,当您针对现有数据库运行时,它将检查__MigrationHistory以查看已应用了哪些迁移。如果数据库不存在,则将创建该数据库。有关详细信息,请参阅here和here。
不确定您在使用MigrationId谈论什么。 EF会自动处理,除非您更改命名空间(此外还有解决方法)。