2013-04-04 29 views
1

我的SQL的理解是非常基本的,我來自的NHibernate的,所以我用這個問題相當不解世界...一一對一映射問題

我有兩個類:

public class UserProfile 
{ 
    public UserProfile() { } 

    [Key] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public SerialNumber Serial { get; set; } 
    // Other properties 
} 

public class SerialNumber 
{ 
    public SerialNumber() 
    { 
     // My code that creates a unique Code 
    } 

    [Key] 
    public string Code { get; set; } 
    public UserProfile User { get; set; } 

    // Other Properties 
} 

我有這個

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    // Other modelBuilder stuff 

    modelBuilder.Entity<UserProfile>() 
     .HasOptional(s => s.Serial) 
     .WithRequired(u => u.User); 
} 

我跑Add-Migration後,我得到這個:

public override void Up() 
{ 
    DropForeignKey("dbo.UserProfile", "Serial_Code", "dbo.SerialNumbers"); 
    DropIndex("dbo.UserProfile", new[] { "Serial_Code" }); 
    RenameColumn(table: "dbo.SerialNumbers", name: "Serial_Code", newName: "User_UserId"); 
    AddForeignKey("dbo.SerialNumbers", "User_UserId", "dbo.UserProfile", "UserId"); 
    CreateIndex("dbo.SerialNumbers", "User_UserId"); 
} 

public override void Down() 
{ 
    // Inverse of above 
} 

我跑Update-Database後,我得到一個錯誤: "Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong."

我可以通過Add-Migration生成的代碼的東西是錯誤的,因爲我的db表沒有按」告訴噸甚至通過"Serial_Code"

我需要Code名稱有一列是我Key作爲的EntityFramework沒有一個選項來執行一列是Unique除了牛逼o讓它成爲關鍵。

如何使Serial是的UserProfileUser一個可選屬性在SerialNumber當它加入到UserProfile被自動設置?

回答

4

默認情況下,在一對一關係中,實體框架要求依賴項上的外鍵也是主鍵。這很可能是由於Entity Framework只在主鍵上設置了唯一約束(或者是因爲它是主鍵而存在唯一約束)。在數據庫級別,一對一沒有映射到關係的兩端,即沒有在兩個表上創建外鍵。當您思考參考完整性如何工作時,這是有道理的:如果刪除關係的一方,則會導致另一方的數據庫崩潰,導致一種無限循環。

因此,外鍵被添加到依賴項,在一對一的情況下,就像你在這裏是具有所需導航屬性的末端:你的SerialNumber模型。這意味着要真正創建一對一而非一對多的密鑰,您的密鑰SerialNumber需要爲User_UserId(自動生成的外鍵列,因爲您沒有手動指定外鍵屬性)。要設置它這樣,你的模型將是這樣的:

public class UserProfile 
{ 
    [Key] 
    public int UserId { get; set; } 

    public SerialNumber Serial { get; set; } 

    ... 
} 

public class SerialNumber 
{ 
    [Key] 
    [ForeignKey("User")] 
    public int UserId { get; set; } 

    public UserProfile User { get; set; } 

    ... 
} 

或用流利的API:

modelBuilder.Entity<SerialNumber>() 
    .HasRequired(m => m.User) 
    .WithOptional(m => m.Serial); 

(你會需要離開關[Key]數據註解,使EF可以使外鍵,他們爲表的主鍵。)

這使得您無需您Code屬性的唯一約束,雖然。你當然也可以手動設置你的桌子上此約束,或者如果你不使用自動遷移,你可以改變你的遷移來建立約束:

CreateIndex("dbo.SerialNumbers", "Code", unique: true); 

這裏的問題是,實體框架不會處理獨特驗證你。因此,您需要在代碼中手動維護完整性(例如,嘗試使用您要保存的Code來查找SerialNumber,並且只有在您沒有從查詢中得到任何回覆時才保存它)。

我知道這是一種痛苦,但現在,這就是你所能做到的。希望EF能夠在未來的版本中解決唯一性問題。

+0

謝謝你這麼詳細的解釋 – 2013-04-04 02:05:30