我们正在使用.NET Core、EF Core和Postgres启动一个新的应用程序--我们非常喜欢迁移:-)
然而,我发现了一个我无法解决的问题。在一些迁移中,我们使用DbContext加载记录,运行一些业务逻辑,并重新保存记录。我们还在web服务器启动时运行database.Context.Migrate(),因此它总是运行。
这一切都很好(到目前为止)。
不幸的是,它一直在工作,直到模型在以后的某个时候被更改。考虑以下迁移顺序:
Customer、Order和OrderLine模型。添加模式迁移以加载结构Order记录上设置一个值。我们创建一个数据迁移,在其中加载DbContext,运行代码,并运行SaveChangesAsync()
在这一点上,一切都好。Customer记录中。在这里,一切都变坏了。如果数据库没有应用迁移2,则Migrate()命令错误,就像应用迁移2时一样,EF试图生成一个select语句,其中包含3中的新字段。
不过,我不知道问题到底在哪里:我们是否应该在迁移中使用DbContext (以及手动代码SQL语句)?我们是否应该明确地在每一次读取的记录上做预测,这样我们才能确切地知道自己在做什么?
还有别的吗?
发布于 2019-10-03 18:10:41
在您的示例中,1和3是架构迁移,2是数据迁移。
由于将根据代码中的当前模型(而不是数据库的当前状态)生成查询,因此有两个处理数据迁移的选项。
DbConnection从EF上下文中获取context.Database.GetDbConnection()对象。
优点:迁移代码永远不需要更改。
缺点:你得不到EF核心的任何好处MigrationAttribute.Id字符串值的升序执行迁移。EF在调用dotnet ef migrations add xxx时基于时间戳生成此值。您可以更改此属性以确保在所有架构迁移之后运行数据迁移。为了可读性,也要更改文件名,这样它们就会按照应用的顺序排列。
优点:你可以得到EF核心的所有好处
缺点:如果模式将来发生变化,例如删除数据迁移中引用的列,则需要修改迁移。
示例MigrationAttribute.Id更改:// change
[Migration("20191002171530_DataMigration")]
// to
[Migration("99999999000001_DataMigration")]发布于 2021-09-27 13:02:25
我面临着一个类似的问题,并在这个问题上,我想我应该分享我的技术,以解决我的问题为后人。
在我的例子中,我们有一个模型Something,最初有一个字段/数据库列property,但是这个字段被废弃了,因为property最终存储在其他地方。我们编写了一个引用Something.property并将其移到新位置的数据迁移。
我们还想更新域模型以从property中删除Something。然而,这样做会破坏数据迁移中的类型转换。
我们必须有一个具有property的类型,以便允许数据迁移到打字机。但是,我们不能在域模型上使用property。
解决方案是引入MigrationDbContext,它是标准DbContext的子类。MigrationDbContext公开了Somethings表的第二个投影,称为Somethings_WithProperty。这个投影是一个public DbSet<SomethingWithProperty>。SomethingWithProperty类是具有当代属性的模型历史类型的记录;重要的是,我们只允许该类型出现在我们的Migrations文件夹中。SomethingWithProperty存储在Migrations/HistoricalModels中。
现在,我的数据迁移从依赖项注入中获得了一个MigrationDbContext,而不是一个DbContext。我可以将对dbcontext.Somethings的引用替换为dbcontext.Somethings_WithProperty,数据迁移可以进行类型检查。另一方面,我的域模型永远不会从MigrationDbContext获得,因此它能得到的唯一Something是来自Somethings DbSet,它正确地忽略了我们删除的property。
几个注意事项;如果您的DbContext构造函数采用一般的DbContextOptions<MyDbContext>参数,那么为了满足依赖注入,您需要在MyDbContext上引入一个接受DbContextOptions<MigrationDbContext>参数的protected构造函数;子类可以在其构造函数中调用该构造函数。另外,MigrationDbContext最初会混淆两个投影映射到同一个表;在它的SetupSomethingsWithProperty方法中,您应该包括一个引用自然投影的外键,以消除混淆。
private static void SetupSomethingsWithProperty(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Something_WithProperty>(s =>
{
s.ToTable("Somethings");
s.HasOne<Something>().WithOne().HasForeignKey<Something_WithProperty>(r => r.ID);
});
}https://stackoverflow.com/questions/58210485
复制相似问题