32

我的MVC應用程序中有兩個實體,並使用實體框架6代碼優先方法填充數據庫。學生實體中有兩個城市ID;其中一個是BirthCity,另一個是WorkingCity。當我像上面那樣定義外鍵時,遷移後在Student表中創建一個名爲City_ID的額外列。是否有錯誤或如何定義這些FK?提前致謝。爲實體框架中的同一表定義多個外鍵代碼首先

學生:

public class Student 
{ 
    public int ID { get; set; } 

    public string Name { get; set; } 

    public string Surname { get; set; } 

    public int BirthCityID { get; set; } 

    public int LivingCityID { get; set; } 


    [ForeignKey("BirthCityID")] 
    public virtual City BirthCity { get; set; } 

    [ForeignKey("LivingCityID")] 
    public virtual City LivingCity { get; set; } 
} 


市:

public class City 
{ 
    public int ID { get; set; } 

    public string CityName { get; set; } 


    public virtual ICollection<Student> Students { get; set; } 
} 
+0

我簡化了我的清晰的代碼,但我的代碼與此完全相似。另一方面,我已經嘗試從頭開始重新創建數據庫2-3次,但現在我再次做同樣的事情,並在幾分鐘內通知您。 – 2015-02-17 21:45:00

+0

@ChrisPratt:以下是我現在遵循的步驟:1)從我的項目中刪除遷移文件夾及其內容。 2)清理並重建解決方案中的所有項目。 3)在Package Manager控制檯上啓用遷移,然後添加AutomaticMigrationsEnabled = true;和AutomaticMigrationDataLossAllowed = true;到配置文件的構造函數。 4)添加遷移。 >>> – 2015-02-17 21:59:27

+0

@ChrisPratt:但是在這一步之後,我再次觀察到在Up方法中有一個屬性「City_ID = c.Int()」。但是,我在解決方案中搜索並沒有「City_ID」屬性。那麼,爲什麼這個未定義的計劃被添加到項目中?提前致謝。 – 2015-02-17 22:01:20

回答

52

public class City 
{ 
    ... 

    public virtual ICollection<Student> BirthCityStudents { get; set; } 
    public virtual ICollection<Student> LivingCityStudents { get; set; } 
} 

然後,Student實現你想要的東西,你需要提供一些輔助配置。代碼第一個約定可以識別雙向關係,但不是當存在多個時,多個 多您可以添加配置(使用數據註釋Fluent API)將此信息提供給模型構建器。使用數據註釋,您將使用名爲InverseProperty的註釋 。使用Fluent API,您將使用Has/With方法的組合來指定這些關係的正確結束。

使用數據註釋可能是這樣的:

public class Student 
{ 
    public int ID { get; set; } 

    public string Name { get; set; } 

    public string Surname { get; set; } 

    public int BirthCityID { get; set; } 

    public int LivingCityID { get; set; } 


    [ForeignKey("BirthCityID")] 
    [InverseProperty("Students")] 
    public virtual City BirthCity { get; set; } 

    [ForeignKey("LivingCityID")] 
    public virtual City LivingCity { get; set; } 
} 

這樣你明確指定要涉及與Students導航屬性的BirthCity導航屬性的關係的另一端。

使用流暢API可能是這樣的:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity) 
           .WithMany(m => m.Students).HasForeignKey(m=>m.BirthCityId); 
    modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity) 
           .WithMany().HasForeignKey(m=>m.LivingCityId); 
} 

隨着你不需要使用任何attibute這最後的解決方案。

現在,@ChristPratt的建議在您的City類中爲每個關係都有一個Student的集合,這真的很有用。如果你這樣做,然後使用數據註釋的配置可能是這樣的:使用流暢API遵循同樣的理念

public class Student 
{ 
    public int ID { get; set; } 

    public string Name { get; set; } 

    public string Surname { get; set; } 

    public int BirthCityID { get; set; } 

    public int LivingCityID { get; set; } 


    [ForeignKey("BirthCityID")] 
    [InverseProperty("BirthCityStudents")] 
    public virtual City BirthCity { get; set; } 

    [ForeignKey("LivingCityID")] 
    [InverseProperty("LivingCityStudents")] 
    public virtual City LivingCity { get; set; } 
} 

或者:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity) 
       .WithMany(m => m.BirthCityStudents).HasForeignKey(m=>m.BirthCityId); 
    modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity) 
       .WithMany(m => m.LivingCityStudents).HasForeignKey(m=>m.LivingCityId); 
} 
+0

非常感謝您的回答。正如你和@ChrisPratt所說的那樣,有兩種方法可以實現這一點,並且兩者都在起作用。由於**數據註釋**的方式似乎更容易控制此操作的實體,我寧願使用這種方式。非常感謝您的考慮。問候... – 2015-02-18 11:18:28

+0

如果學生和城市之間的關係是1 - > 0..1怎麼辦? 你怎麼能實現與流利的API – 2015-09-30 11:35:16

+0

@PaulSodimu,看看這個[頁](https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449317867/ch04s07.html)。你將在那裏找到你的答案 – octavioccl 2015-09-30 11:56:17

15

嘖。這是一個漫長的一天。實際上,你的代碼實際上有一個非常大的問題,當我評論時我完全錯過了。

問題是您使用City的學生的單一集合。這裏實際發生的事情是,EF無法確定它應該將該集合實際映射到哪個外鍵,因此它會創建另一個專門用於跟蹤該關係的外鍵。然後,實際上,您對BirthCityLivingCity派生的學生沒有導航屬性。

爲此,您必須下降到流暢的配置,因爲沒有辦法使用數據註釋來正確配置它。您還需要學生額外的收藏,您可以跟蹤的關係:在上下文

public class Student 
{ 
    ... 

    public class StudentMapping : EntityTypeConfiguration<Student> 
    { 
     public StudentMapping() 
     { 
      HasRequired(m => m.BirthCity).WithMany(m => m.BirthCityStudents); 
      HasRequired(m => m.LivingCity).WithMany(m => m.LivingCityStudents); 
     } 
    } 
} 

最後:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Configurations.Add(new Student.StudentMapping()); 
} 
+0

非常感謝您的回答。正如你和@octavioccl所說的那樣,有兩種方法可以實現這一點,並且兩者都在工作。由於* Data Annotations *方法似乎更容易控制此操作的實體,因此我寧願使用這種方式。非常感謝您的考慮。問候... – 2015-02-18 11:19:21

+0

感謝'StudentMapping'類...我一直在摔跤這些定義應該居住在哪裏,我真的很喜歡他們是從'學生'類可見 - 信息是相關的 - 不是在上下文。 – erroric 2015-09-25 13:50:27

+1

@erroric:是的,我不記得最初我在哪裏遇到過這種情況,但是隨着每個單獨的教程隨處可見,它遠遠超過了上下文。在發現這種方法之前,流暢配置的最大問題是它不在實體中,所以除非您注意到哪些實體是通過上下文配置的,否則會導致很多混淆。 – 2015-09-25 14:43:14

相關問題