簡體   English   中英

Entity Framework 6 FluentApi 一對一關系配置

[英]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 不在數據庫中的實體上的一對一關系。

https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

EF6 自然只支持使用所謂的共享主鍵關聯的一對一關系,其中依賴的 PK 也用作 FK。 但是,它們不適用於這種情況(當您需要兩個實體之間的多個一對一關系時)。 因此,您需要基於 FK 的一對一關系。

它們受支持,但有以下限制:

  • EF6 不會在數據庫中強制執行“到 1”(或“到 0 或 1”)所需的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM