【发布时间】:2014-04-07 10:59:28
【问题描述】:
我遇到了与查找表和外键相关的 EF 代码优先迁移问题。假设我的代码中有这两个类:
public class Test
{
[Key]
public long Id { get; set; }
[Required]
public string Title { get; set; }
[Required, DisplayName("Test type")]
public TestType TestType { get; set; }
}
public class TestType
{
public int Id { get; set; }
public string Name { get; set; }
}
TestType 是一个典型的查找表,我通常用Seed() 方法填充它们:
context.TestTypes.AddOrUpdate(
it => it.Name,
new TestType() { Name = "Drug" },
new TestType() { Name = "Educational" },
new TestType() { Name = "Other" }
);
当我创建具有关系的表时,我得到以下迁移:
CreateTable(
"dbo.TestTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
现在,如果我执行迁移,我当然会收到一个错误,因为鉴于查找表仍然为空并且创建的列没有默认值,因此无法尊重外键。
在开发中,我可以通过简单地创建两个迁移来解决这个问题,第一个用于创建查找表,第二个用于设置外键。如果我单独运行它们,那么第一个之后的 Seed 方法将填充表,我可以调整列创建以从数据库中获取值以在创建外键之前预填充列,有点像这样:
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
Sql("UPDATE dbo.Tests SET TestType_Id = (SELECT TOP 1 Id FROM dbo.TestTypes)");
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
然后当我运行它时,一切正常。
现在,在 PRODUCTION 中我没有同样的奢侈,因为所有迁移都是在运行 Seed 方法之前运行的,所以我总是会遇到同样的问题。
我知道我也可以可能在生产数据库上按步进顺序运行迁移,但这并不能真正解决问题...假设我的一位同事更新了他的工作副本并运行迁移,一切都会按顺序运行,他肯定会遇到错误。
【问题讨论】:
-
TestType 也不应该创建表吗?
-
@Tallmaris 你有没有找到一个好的解决方案?
-
并非如此。我基本上可以选择为新列设置
nullable:true,然后在将来进行调整(这并不理想),或者只是将种子添加到迁移本身,因为它们彼此紧密相连。
标签: c# asp.net-mvc entity-framework ef-code-first entity-framework-migrations