c# - EF 代码首先使用空查找表设置外键

标签 c# asp.net-mvc entity-framework ef-code-first entity-framework-migrations

我遇到与查找表和外键相关的 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);

现在,如果我执行迁移,我当然会得到一个错误,因为鉴于查找表仍然是空的并且创建的列没有默认值这一事实,外键无法得到尊重。

DEVELOPMENT 中,我可以通过简单地创建两个迁移来解决这个问题,第一个迁移创建查找表,第二个迁移设置外键。如果我单独运行它们,那么第一个方法之后的 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 方法运行之前运行,所以我总是会遇到同样的问题。

我知道我也可以可能在生产数据库上按步进顺序运行迁移,但这并不能真正解决问题...假设我的一位同事更新了他的工作副本并运行迁移,一切都将按顺序运行,他肯定会遇到错误。

最佳答案

我不确定你的数据库的当前状态,但我会这样定义你的模型

public class Test
{
    [Key]
    public long Id { get; set; }

    [Required]
    public string Title { get; set; }

    [Required]
    [ForeignKey("TestType")]
    public int TestTypeId { get; set; }

    [DisplayName("Test type")]
    public virtual TestType TestType { get; set; }
}

public class TestType
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
}

当表尚不存在时,这会导致以下迁移。我总是发现明确描述外键效果更好。

public override void Up()
{
    CreateTable(
        "dbo.Tests",
        c => new
            {
                Id = c.Long(nullable: false, identity: true),
                Title = c.String(nullable: false),
                TestTypeId = c.Int(nullable: false),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.TestTypes", t => t.TestTypeId)
        .Index(t => t.TestTypeId);

    CreateTable(
        "dbo.TestTypes",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Name = c.String(),
            })
        .PrimaryKey(t => t.Id);
}

只要 Test 表为空,种子就可以正常工作?

关于c# - EF 代码首先使用空查找表设置外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22196855/

相关文章:

c# - 启动 C# 应用程序后,非主线程执行什么操作?

c# - 寻找集体智慧 .Net/C# 资源

c# - 如何更改 ExceptionContext 自定义属性的重定向 View ?

c# - 如何从存储过程结果 Entity Framework 创建列表

jquery - Ajax 调用不加载页面而是进入 .fail?

sql-server - 存储数据提供程序返回的数据读取器没有足够的列用于请求的查询

c# - 表拆分 - 是否可以将表拆分为两个完全独立的实体?

c# - MVVM 的正确方法

c# - 使用来 self 的 API 的访问 token 对 C# MVC Web 应用程序进行身份验证的最佳方法

c# - 有谁知道 EF6 和 AutoMapper 进行枚举转换时发生了什么