2013-05-27 136 views
0

我試圖讓一對一的關係。如果沒有必要,我不想使用流利的API。這是我到目前爲止的嘗試:一對一的關係 - 代碼優先

[Table("UserProfile")] 
public class UserProfile 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
} 
    public class Person 
{ 
    public int Id { get; set; } 

    [ForeignKey("UserId")] 
    public UserProfile UserProfile { get; set; } 

} 

是的,我知道有幾個類似的問題,但沒有一個是簡短和明確的。他們中的很多人也沒有工作。

+1

謝謝.Down投票幫助。 –

+0

我們可以檢查您正在使用的MVC和EF版本 - 這可能與您的答案有關。 –

+0

MVC 4,實體框架5 –

回答

4

這取決於一點你想要實現什麼類型的表結構。有多種方式可以做到這一點,並且在這些鏈接中有從Shared Primary Key AssocationsOne-to-One Foreign Key Associations的所有選項都有很好的演練。不幸的是,這些鏈接比註釋更多地使用Fluent。根據需要,下面的示例使用註釋。

共享主鍵

理論上共享主密鑰(水平表分區,數據庫而言)是「正確的方式」。這也是您需要做的最小的更改,以便能夠生成遷移(將使用共享主鍵關聯)。請注意,我會改變Person.IdPerson.UserId更好地展現你的意圖:

// tested in EF 5 and MVC 4.5. 
[Table("UserProfile")] 
public class UserProfile { 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
} 
[Table("Person")] // not required, added for clarity in sample code 
public class Person { 
    // Note the change of property name to reflect that this is a shared primary key, 
    // using the UserId column in UserProfile as the Primary Key 
    [Key] 
    public int UserId { get; set; } 
    [ForeignKey("UserId")] 
    public virtual UserProfile UserProfile { get; set; } 
} 
// The generated migration: 
public partial class AddTable_Person : DbMigration 
{ 
    public override void Up() { 
     CreateTable(
      "dbo.Person", 
      c => new { 
        UserId = c.Int(nullable: false), 
       }) 
      .PrimaryKey(t => t.UserId) 
      .ForeignKey("dbo.UserProfile", t => t.UserId) 
      .Index(t => t.UserId); 
    } 
    public override void Down(){ 
     DropIndex("dbo.Person", new[] { "UserId" }); 
     DropForeignKey("dbo.Person", "UserId", "dbo.UserProfile"); 
     DropTable("dbo.Person"); 
    } 
} 

這就給你,實際上UserProfile之間People一個1:0-1關係(這是強制的)(這是可選的,但可以有一個每人在最

如果你想使用PersonId然後執行以下操作(遷移將發生相應的變化)。

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

    [ForeignKey("Id")] 
    public UserProfile UserProfile { get; set; } 
} 

共享主鍵與雙向導航

如果你要離開UserProfilePerson你有更多的工作要做。簡單地增加public virtual Person Person { get; set; }到用戶配置會給你一個錯誤:

Unable to determine the principal end of an association between the types 'Test.Models.UserProfile' and 'Test.Models.Person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

因此,我們與[Required]修復它的Person.UserProfile財產(Person需要UserProfile)。這提供了與以前相同的遷移。

// tested in EF 5 and MVC 4.5. 
[Table("UserProfile")] 
public class UserProfile { 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    [ForeignKey("UserId")] 
    public virtual Person Person { get; set; } 
} 
[Table("Person")] // not required, added for clarity in sample code 
public class Person { 
    [Key] 
    public int UserId { get; set; } 
    [ForeignKey("UserId")] 
    [Required] 
    public virtual UserProfile UserProfile { get; set; } 
} 

再次,這工作,如果你使用IdPerson代替UserId

public class Person { 
    [Key] 
    public int Id { get; set; } 
    [ForeignKey("Id")] 
    [Required] 
    public virtual UserProfile UserProfile { get; set; } 
} 
+0

+1:良好的分析!我發現奇怪的是,對於在Person.UserId上添加'[ForeignKey(「UserProfile」)]'的雙向導航,沒有'[Required]'屬性而沒有'UserProfile'中的FK屬性,但它沒有除非你刪除UserProfile.Person導航屬性,否則在'Person.UserProfile'上不需要'[Required]'屬性的'[ForeignKey(「UserId」)]'。完全讓我困惑...... – Slauma

+0

@Slauma。它的確如此,儘管我更喜歡虛擬UserProfile屬性中的'Required',因爲它有助於聲明意圖 - 儘管如此,純粹是個人偏好。 –

0
[Table("UserProfile")] 
public class UserProfile 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public virtual Person Person {get;set;} 
} 

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

    public int UserProfileUserId { get; set; } //Foreign Key 
    public virtual UserProfile UserProfile { get; set; } 
} 
+0

它不起作用。這就是爲什麼我說這個話題真的有很多不正確的答案。這就是爲什麼我非常喜歡那個沮喪的人。 –

+0

@impeRAtoR:哦,我忘了編輯你的userProfile類...現在檢查... –

0

如果你想建立一對一的關係,你必須首先明確什麼是這個關係中的主體和依賴實體。 Person可以存在沒有UserProfile或可以存在UserProfile沒有Person

因爲你已經開始在Person申請一個[ForeignKey]屬性我現在假設Person是相關的,即它不能沒有UserProfile存在。然後

[ForeignKey]屬性的正確應用是:

public class Person 
{ 
    [ForeignKey("UserProfile")] 
    public int Id { get; set; } 

    public UserProfile UserProfile { get; set; } 
} 

我不知道這是不夠的,因爲你沒有在UserProfile一個Person導航屬性。如果它不工作,這個屬性添加到UserProfile

如果你不希望有這樣的導航屬性無法避免流利的API:

modelBuilder.Entity<Person>() 
    .HasRequired(p => p.UserProfile) 
    .WithOptional(); 
+0

恕我直言,modelBuilder.Entity () .HasRequired(p => p.UserProfile) .WithOptional();'是FLUENT API代碼,用戶不想使用.. –

+0

我可以使用流利的api,這不是問題,我也想導航屬性,是的,沒有UserProfile的人不能存在 –

+0

@BhushanFirake:「*如果沒有必要*「, 他說。但是,如果他不想擁有「UserProfile.Person」導航屬性(可能)是必需的。他有以下選擇:導航屬性或Fluent API。可能它沒有必要,即使沒有導航屬性也是如此,因爲FK屬性指的是PK,也許EF足夠聰明地發現一個PK在同一時間只能參與一對一的關係。我不確定這一點。 – Slauma