簡體   English   中英

實體框架:代碼中的外鍵優先

[英]Entity Framework: Foreign Key in code first

我得到以下錯誤的代碼是什么錯誤:

無法確定相關操作的有效順序。 由於外鍵約束,模型要求或商店生成的值,可能存在依賴關系

碼:

類食品:

public class Food
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public short Id { get; set; }

    //some Property
    public string Name { get; set; }

    public virtual ICollection<Person> Persons { get; set; }
}

班級人員:

public class Person
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    //some Property
    public string FirstName { get; set; }

    [ForeignKey("BestFoodId")]
    public Food BestFood { get; set; }
    public short BestFoodId { get; set; }

    public virtual ICollection<Food> FavoriteFoods { get; set; }
}

播種方法:

 protected override void Seed(MyContext context)
    {
        Food food1 = new Food() { Name = "foo1" };
        Food food2 = new Food() { Name = "foo2" };
        Food food3 = new Food() { Name = "foo3" };

        context.Persons.AddOrUpdate(new Person()
        {
            FirstName = "Jack",
            BestFood = food2,
            FavoriteFoods = new List<Food>() { food1, food2, food3 }
        });

    }

錯誤原因:關聯混亂

發生這種情況是因為按照慣例,實體框架假定Person.BestFoodId逆屬性Food.Persons 換句話說: Person.BestFoodFood.Persons被認為是一對多關聯的兩端,具有Person.BestFoodId作為外鍵。

您可以通過向[InverseProperty]添加[InverseProperty]屬性來進行BestFood

public class Person
{
    ...
    [ForeignKey("BestFoodId")]
    [InverseProperty("Persons")]
    public Food BestFood { get; set; }
    ...
}

這將導致相同的錯誤。

此錯誤-沒有有效的訂購-始終表示雞和蛋的問題。 在您的情況下,EF嘗試插入需要插入人生成的ID作為外鍵的食物,而插入人需要插入的foo2食物的生成ID。

解決方案:顯式映射的關聯

在現實中, PersonFood有兩個協會:

  • 1-n: Food可以是n人的BestFood Food
  • nm:n Food可以成為m人FavoriteFoodsFood

在您的模型中, BestFood沒有逆屬性,這可能是因為...

public virtual ICollection<Person> BestFoodOf { get; set; }

...但是這不是必需的,因為它丟失了,所以它掩蓋了EF如何推斷關聯。

您可以通過顯式映射關聯來解決此問題,例如在DbContext子類的OnModelCreating覆蓋中:

modelBuilder.Entity<Person>()
            .HasRequired(p => p.BestFood)
            .WithMany() // No inverse property
            .HasForeignKey(p => p.BestFoodId)
            //.WillCascadeOnDelete(false)
            ;

modelBuilder.Entity<Person>()
            .HasMany(p => p.FavoriteFoods)
            .WithMany(f => f.Persons)
            .Map(m => m.MapLeftKey("PersonId")
                       .MapRightKey("FoodId")
                       .ToTable("PersonFavoriteFood"));

我已經注釋掉WillCascadeOnDelete(false) 您要么添加此行,要么添加...

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

...以防止出現多個級聯的刪除路徑(SQL Server的限制)。

將其放置在適當的位置后,EF知道如何確定插入的有效順序:它將首先插入食物,然后插入人(使用生成的foo2 Id作為外鍵),然后在PersonFavoriteFood表中連接記錄。

看起來您具有循環依賴關系。

答案在這里:


可選改進:

  • 您應該將導航屬性聲明為virtual

  • 如果使用的是C#6.0或更高版本,請將[ForeignKeyAttribute]數據注釋定義更改為[ForeignKey([nameof(BestFoodId))]以避免使用硬編碼的屬性名稱出錯。 nameof是一個非常酷的編譯器功能! :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM