[英]Entity Framework 6 FluentApi One-to-One Relationship configuration
[Table("Child", Schema = "dbo")]
public partial class Child
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public int? Parent1Id { get; set; }
public int? Parent2Id { get; set; }
public virtual Parent Parent1 {get; set}
public virtual Parent Parent2 {get; set}
}
[Table("Parent", Schema = "dbo")]
public partial class Parent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public virtual Child Child1 { get; set; }
public virtual Child Child2 { get; set; }
//modelBuilder below would work if I had this
//public virtual ICollection<Child> Child1 { get; set; }
}
這意味着父子之間是一對一的關系。 Parent1Id 和 Parent2Id 可以為空。
我只找到了一對多關系的示例(使用 FluentAPI),如果我在 Parent 中有一個 Child 集合,我必須執行以下操作:
modelBuilder.Entity<Parent>()
.HasMany(e => e.Child1)
.WithOptional(e => e.Parent1)
.HasForeignKey(e => e.Parent1Id);
modelBuilder.Entity<Parent>()
.HasMany(e => e.Child2)
.WithOptional(e => e.Parent2)
.HasForeignKey(e => e.Parent2Id);
孩子將有 2 個 FK 參考父母。 父級沒有引用子級的 FK。
我的問題是,如何使用 EF 6.x 以一對一的關系做到這一點? 我看到了 HasOne() 方法,但它來自 EFCore,所以我在這個方法中沒有選擇。
謝謝
注意:從技術上講,MS SQL 服務器中的一對一關系是不可能的。 這些將始終是一對零或一的關系。 EF forms 不在數據庫中的實體上的一對一關系。
EF6 自然只支持使用所謂的共享主鍵關聯的一對一關系,其中依賴的 PK 也用作 FK。 但是,它們不適用於這種情況(當您需要兩個實體之間的多個一對一關系時)。 因此,您需要基於 FK 的一對一關系。
它們受支持,但有以下限制:
HasForeignKey
fluent API)。 您必須刪除它們並僅使用導航屬性。 可以使用MapKey
方法中的Map
指定 FK列名稱。您必須接受這些限制,否則您不能將 EF6 與此類 model 一起使用。
首先從 model 中刪除顯式 FK 屬性:
// remove these:
//public int? Parent1Id { get; set; }
//
//public int? Parent2Id { get; set; }
接下來要考慮的是 EF 關系始終認為一方是主要的,另一方是依賴的。 在一對多中,“一”方始終是主體,“多”方始終是從屬。 對於一對一,通常需要的一端是主體,可選的一端是依賴端,但是當兩端都是必需的或兩端都是可選的(如您的情況)時,您必須使用適當的WithRequired
/ WithOptional
方法,其中Principal
/ Dependent
后綴指定如何對待正在配置的實體( Has
方法的泛型類型參數)。 這很重要,通常會讓人感到困惑,因為 Map 內部的流利配置的Map
始終適用於依賴實體,無論使用哪個實體來啟動配置。
話雖如此,在您的示例中,有兩種關系, Parent
都是委托人, Child
是受撫養人,兩端都是可選的。 因此流暢的配置可以是
modelBuilder.Entity<Parent>()
.HasOptional(p => p.Child1)
.WithOptionalPrincipal(c => c.Parent1)
.Map(c => c.MapKey("Parent1Id"));
modelBuilder.Entity<Parent>()
.HasOptional(p => p.Child2)
.WithOptionalPrincipal(c => c.Parent2)
.Map(c => c.MapKey("Parent2Id"));
它也可以通過其他方式配置:
modelBuilder.Entity<Child>()
.HasOptional(c => c.Parent1)
.WithOptionalDependent(p => p.Child1)
.Map(c => c.MapKey("Parent1Id"));
modelBuilder.Entity<Child>()
.HasOptional(c => c.Parent2)
.WithOptionalDependent(p => p.Child2)
.Map(c => c.MapKey("Parent2Id"));
注意:使用一個或另一個,不要同時使用。 通常關系配置從具有導航屬性的一端開始(因為它是Has
方法所必需的),但是當兩端都有導航時,這只是個人喜好/品味的問題。
父母是委托人,孩子是受撫養人,因此孩子需要父母,但孩子對父母來說是可選的:
modelBuilder.Entity<Child>()
.HasRequired(c => c.Parent1)
.WithOptional(p => p.Child1)
.HasForeignKey(c => c.Parent1Id);
通常,您會使用受撫養人的 PK 作為主體實體的 FK(這是確保一對一關系的原因),但您在這里嘗試一些不尋常的事情 - 您似乎想要一對二的關系. 我的意見是重新考慮您的設計 - 使其成為 1:N 並限制應用程序/DbContext 代碼中的依賴項數量或從Child
派生兩種不同類型,以便它們是 DB/ERM model 中的不同實體,然后使用標准“PK作為 FK”的一對一映射。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.