2015-12-20 62 views
4

我需要一對一(可選)。爲什麼EF生成外鍵?

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<PinnacleAccount>().HasKey(x => x.Id); 

    modelBuilder.Entity<PinnacleAccount>() 
     .HasRequired(x => x.User) 
     .WithOptional(x => x.PinnacleAccount); 

    base.OnModelCreating(modelBuilder); 
} 

,當我運行「添加 - 遷移初始化」我檢查產生的遷移和看到:

CreateTable(
       "dbo.PinnacleAccounts", 
       c => new 
        { 
         Id = c.Int(nullable: false, identity: true), 
         ClientId = c.String(), 
         Password = c.String(), 
         PercentForBet = c.Int(nullable: false), 
         UserId = c.String(), 
         User_Id = c.String(nullable: false, maxLength: 128), 
        }) 
       .PrimaryKey(t => t.Id) 
       .ForeignKey("dbo.AspNetUsers", t => t.User_Id) 
       .Index(t => t.User_Id); 

但我有屬性用戶ID。爲什麼根據慣例EF創建USER_ID

public class ApplicationUser : IdentityUser 
    { 
     public virtual PinnacleAccount PinnacleAccount { get; set; } 
     public int? PinnacleAccountId { get; set; } 

     public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) 
     { 
      // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType 
      var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); 
      // Add custom user claims here 
      return userIdentity; 
     } 
    } 
+0

'User'實體是怎麼樣的? – JotaBe

+0

請添加所有相關代碼。 – JotaBe

回答

4

當您在實體框架中建立1:0.1關係時,第一個實體的主鍵必須與第二個實體的主鍵相同。您無法指定哪個屬性是FK,因爲它不是必需的。我將解釋:

如果User只有一個PinnacleAccount,它是1:0.1的關係。所以,每PinnacleAccount屬於User。這意味着,PinnacleAccount是一個弱實體,所以它的主鍵也是一個User外鍵。

PinnacleAccount不應該有它自己的Id,只是UserId。所以,PinnacleAccount應該是這樣的:

public class PinnacleAccount 
{ 
    public string UserId { get; set; } //PK AND FK 
    public string ClientId { get; set; } 
    public string Password { get; set; } 
    public string PercentForBet { get; set; } 
} 

映射:

modelBuilder.Entity<PinnacleAccount>().HasKey(x => x.UserId); 
modelBuilder.Entity<User>() 
    .HasOptional(i => i.PinnacleAccount) 
    .WithRequired(x => x.User); 

這是爲了使1的唯一途徑:0.1的關係。

希望它有幫助!

+0

再次解決EF實體關係問題的最佳方法是僅翻轉關係:) –

+0

This是正確的答案,但我已經創建了一個後續答案,該答案顯示瞭如果先前存在的情況下糾正關係的方式。 – SteveA

1

如你所知EF創建模型,以及相應的遷移,屬性和流利的API你使用。而且,除非另有說明,否則該公約只是內置的慣例,在大多數場合中都能正常工作。

因爲您沒有指定FK屬性的明確性,所以正在使用約定。 「慣常」慣例將選擇UserId作爲FK。然而,有一個類型不匹配,因爲PinnacleAccountUserId是一個簡單的字符串,同時,根據創建User_Id,在AspNetUsers表的主鍵,UserId是lenght的字符串128

所以,如果你將UserId的長度定義爲128,使用[MaxLenght]屬性或使用流暢的API .hasMaxLength(),約定將使用它作爲主鍵。

+0

Doen't工作。現在我有UserId和User_Id具有相同的屬性128並且請求 – Mediator

+0

無法在1:0.1關係中指定FK屬性 –

2

也許你需要在模型映射到申報的關係

this.HasOptional(t => t.User) 
       .WithMany(t => t.PinnacleAccount) 
       .HasForeignKey(d => d.UserId); 
+0

這是不對的,因爲OP想要建立一對一的關係。用戶沒有「許多PinnacleAccount」 –

0

@Fabio斯給了正確的答案,但已經有一個不正確的關係建立,需要糾正的人,這裏是如何我做的。

我「PinnacleAccount」看起來像下面的(我用的GUID,但你的想法):

public class PinnacleAccount 
{ 
    [Required] 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public Guid Id { get; set; } 

    public virtual ApplicationUser User { get; set; } 
    [Required] 
    public virtual string UserId { get; set; } 
} 

我可以從PinnacleAccount訪問用戶,而不是周圍的其他方式,這是我想要的糾正。爲此,我必須創建兩個遷移。

首先,我編輯被UserIdOld的UserID屬性和創建看起來像遷移:

public override void Up() 
{ 
    DropForeignKey("dbo.PinnacleAccount", "UserId", "dbo.AspNetUsers"); 
    DropIndex("dbo.PinnacleAccount", new[] { "UserId" }); 
    RenameColumn(table: "dbo.PinnacleAccount", name: "UserId", newName: "User_Id"); 
    AddColumn("dbo.PinnacleAccount", "UserIdOld", c => c.String(nullable: false)); 
    AlterColumn("dbo.PinnacleAccount", "User_Id", c => c.String(maxLength: 128)); 
    CreateIndex("dbo.PinnacleAccount", "User_Id"); 
    AddForeignKey("dbo.PinnacleAccount", "User_Id", "dbo.AspNetUsers", "Id"); 
} 

public override void Down() 
{ 
    DropForeignKey("dbo.PinnacleAccount", "User_Id", "dbo.AspNetUsers"); 
    DropIndex("dbo.PinnacleAccount", new[] { "User_Id" }); 
    AlterColumn("dbo.PinnacleAccount", "User_Id", c => c.String(nullable: false, maxLength: 128)); 
    DropColumn("dbo.PinnacleAccount", "UserIdOld"); 
    RenameColumn(table: "dbo.PinnacleAccount", name: "User_Id", newName: "UserId"); 
    CreateIndex("dbo.PinnacleAccount", "UserId"); 
    AddForeignKey("dbo.PinnacleAccount", "UserId", "dbo.AspNetUsers", "Id", cascadeDelete: true); 
} 

這讓我騰出用戶ID列名稱和它填充了用戶ID user_id列(如那是更改聲明)。

我再變的類看起來像:

public class PinnacleAccount 
{ 
    public string UserId { get; set; } 

    public virtual ApplicationUser User { get; set; } 
} 

其次改變到映射由@Fabio Luz的說明。

我然後創建看起來像第二遷移:

public override void Up() 
{ 
    DropIndex("dbo.PinnacleAccount", new[] { "User_Id" }); 
    RenameColumn(table: "dbo.PinnacleAccount", name: "User_Id", newName: "UserId"); 
    DropPrimaryKey("dbo.PinnacleAccount"); 
    AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(nullable: false, maxLength: 128)); 
    AddPrimaryKey("dbo.PinnacleAccount", "UserId"); 
    CreateIndex("dbo.PinnacleAccount", "UserId"); 
    DropColumn("dbo.PinnacleAccount", "Id"); 
    DropColumn("dbo.PinnacleAccount", "UserIdOld"); 
} 

public override void Down() 
{ 
    AddColumn("dbo.PinnacleAccount", "UserIdOld", c => c.String(nullable: false)); 
    AddColumn("dbo.PinnacleAccount", "Id", c => c.Guid(nullable: false, identity: true)); 
    DropIndex("dbo.PinnacleAccount", new[] { "UserId" }); 
    DropPrimaryKey("dbo.PinnacleAccount"); 
    AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(maxLength: 128)); 
    AddPrimaryKey("dbo.PinnacleAccount", "Id"); 
    RenameColumn(table: "dbo.PinnacleAccount", name: "UserId", newName: "User_Id"); 
    CreateIndex("dbo.PinnacleAccount", "User_Id"); 
} 

這給了我正確的1:0.1。感謝Fabio展示如何正確創建一個!