5

在我看來,像ForeignKey屬性不是爲我工作,但我想我使用它錯了;)實體框架代碼優先外鍵問題

它很容易與代碼解釋:

public class BaseCard 
{ 
    public int Id {get ; set; } 
    public int BaseCardId { get; set; } 

    public List<Skill> Skills { get; set; } 
} 

public class Skill 
{ 
    public int Id { get; set; } 

    public int BaseCardId { get; set; } 
    [ForeignKey("BaseCardId")] 
    public BaseCard BaseCard { get; set; } 
} 

當我嘗試填補種子法這些對象,我得到這個錯誤:

INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Skills_dbo.BaseCards_BaseCardId". The conflict occurred in database "Database", table "dbo.BaseCards", column 'Id'.

在我看來,像ForeignKeySkill次​​嘗試指向的BaseCards,而不是BaseCardIdId列,我想不通爲什麼..

如果我嘗試刪除的BaseCard「正常」 Id屬性,並設置BaseCardId爲PK(帶屬性[Key]),我收到以下錯誤:

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

有誰知道我能得到這個代碼的工作,所以從Skill類物業BaseCardId將指向BaseCardBaseCardId財產,而不是顯然是Id財產?

在此先感謝!

+0

爲什麼你的BaseCard對象有Id和BaseCardId字段? – Sefa

+0

@vgSefa我將BaseCardId設置爲某個數字。我想,這個ID是自動生成的。但它需要是一個具體的數字。是否可以將Id設置爲特定的數字? – Rob

+0

@vgSefa我試圖將Id而不是BaseCardId設置爲我需要的數字,不幸的是,這不起作用。 – Rob

回答

7

您可以自己設置BaseCard的Id,但首先您必須使用Fluent Api來指定此和一對多關係。而且,通過這種方式,您不必在模型類中指定屬性。你的模型類會是這樣的:

public class BaseCard 
{ 
    public int Id {get ; set; } 

    public virtual ICollection<Skill> Skills { get; set; } 
} 

public class Skill 
{ 
    public int Id { get; set; } 

    public int BaseCardId { get; set; } 
    public virtual BaseCard BaseCard { get; set; } 
} 

正如你所看到的,我改變源於作爲virtual.If定義您的導航屬性爲虛擬EF會在運行時創建一個新的類(動態代理)的導航屬性您的BaseCard類並使用它(與Skill一樣)。這個新的動態創建的類包含第一次訪問時加載導航屬性的邏輯。此功能稱爲延遲加載。它使Entity Framework能夠避免加載從數據庫不需要的整個依賴對象樹。你可以在這些帖子中找到關於這個主題的更多信息:Why Navigation Properties are virtual by default in EFEntity Framework 4.1 Virtual Properties

我在您的模型中支持的另一個更改是在技能屬性中使用ICollection <>類型代替列表<>。正如你在這個post中看到的那樣,在這種情況下,一個接口是很好的做法。它可以讓你稍後指定你想要的實現(可以是List <>)。

現在,回到您的問題,在您的Context類中,您需要重寫OnModelCreating方法以在BaseCards表中爲Id指定關係和no autogenerate列。

public class YourContext : DbContext 
{ 
    public DbSet<BaseCard> BaseCards { get; set; } 

    public DbSet<Skill> Skill { get; set; } 

    //... 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // Configure the primary key for BaseCard 
     modelBuilder.Entity<BaseCard>().HasKey(t => t.Id); 
     //specify no autogenerate the Id Column 
     modelBuilder.Entity<BaseCard>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 

     //one-to-many relationship 
     modelBuilder.Entity<Skill>().HasRequired(c => c.BaseCard) 
       .WithMany(s => s.Skills) 
       .HasForeignKey(c => c.BaseCardId); 
    } 
} 

使用此配置,您必須始終設置具有不同值的BaseCard對象的Id。

如果你喜歡使用的數據註解,可以指定同樣在這樣:

public class BaseCard 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int Id { get; set; } 
    public virtual ICollection<Skill> Skills { get; set; } 
} 

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

    public int BaseCardId { get; set; } 

    [ForeignKey("BaseCardId")] 
    public virtual BaseCard BaseCard { get; set; } 
} 

我recomendation是用流利的API,它更靈活,你不必去觸摸你的模型類。你可以看到這個post

+0

非常感謝您的詳細解釋,並給我更多的1個選項。我要做更多的研究,看看我將要使用哪一個。再次感謝。 – Rob

+0

octavioccl,當我使用Fluent API時,在調用update-database -verbose時出現錯誤。這將從遷移中調用Seed方法。在這裏,我嘗試填充數據庫,但是當將BaseCard保存到上下文時,出現以下錯誤:IDENTITY_INSERT設置爲OFF時,無法在表'BaseCards'中插入標識列的顯式值。這是因爲OnModelCreating方法在遷移到數據庫時沒有被調用?你還建議我可以填寫數據庫嗎? – Rob

+0

您是否刪除舊數據庫並創建一個新數據庫?我認爲這是因爲你有一箇舊數據庫,其BaseCards列ID爲Identity。 – octavioccl