简体   繁体   中英

EF Code first set a foreign key with an empty lookup table

I have a problem with EF code first migration related to a lookup table and foreign keys. Let's say I have this two classes in my code:

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 is a typical lookup table and I usually fill them up in the Seed() method:

context.TestTypes.AddOrUpdate(
    it => it.Name,
    new TestType() { Name = "Drug" },
    new TestType() { Name = "Educational" },
    new TestType() { Name = "Other" }
);

When I create the table with the relationship I get the following migration:

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);

Now, if I perform the migration of course I will get an error since the foreign key cannot be respected given the fact that the lookup table is still empty and the column created does not have a default value.

In DEVELOPMENT I am able to solve this by simply creating two migrations, the first one to create the lookup table and the second one to set the foreign key. If I run them separately then the Seed method after the first one will fill the table and I can tweak the column creation to pick up the values from the DB to prefill the column before creating the foreign key, a bit like this:

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);

Then when I run it everything works.

Now, in PRODUCTION I don't have the same luxury, since ALL the migrations are run before the Seed method is run, I will always have the same problem.

I know I could potentially run the migrations in stepped order on the production DB as well but that does not really solve the problem... Let's say a colleague of mine updates his working copy and runs the migrations, all will be run in order and he will encounter the error for sure.

I'm not sure on the current state of your database but I would define your models like this

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; }
}

Which results in the following migration when the tables don't exist already. I always find describing the foreign keys explicitly works better.

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);
}

The seed should then work fine as long as the Test table is empty?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM