2011-10-28 32 views
2

我有一個關係存儲在單獨的連接表中的我的表之一定義了層次關係。連接表還包含有關關係類型的信息。 (簡化)模式如下所示:在實體框架中定義分層數據的關係代碼優先

Bills 
    ID int IDENTITY(1,1) NOT NULL (PK) 
    Code varchar(5) NOT NULL 
    Number varchar(5) NOT NULL 
    ... 

BillRelations 
    ID int IDENTITY(1,1) NOT NULL (PK) 
    BillID int NOT NULL 
    RelatedBillID int NOT NULL 
    Relationship int NOT NULL 
    ... 

我在Bills表中將BillID和RelatedBillID上的FK關係定義爲ID。

我試圖在實體框架代碼優先映射這一點,並沒有取得成功。我的課程如下所示。忽略RelationshipWrapper的東西,這是一個圍繞enum的名爲Relationship的包裝類,它對應於Relationship列中的值。

public class Bill 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int ID { get; set; } 

    [Required] 
    [StringLength(5)] 
    public string Code { get; set; } 

    [Required] 
    [StringLength(5)] 
    public string Number { get; set; } 

    public virtual ICollection<BillRelation> RelatedBills { get; set; } 

    ... 
} 

public class BillRelation 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int ID { get; set; } 

    public long BillID { get; set; } 

    [ForeignKey("BillID")] 
    public virtual Bill Bill { get; set; } 

    public long RelatedBillID { get; set; } 

    [ForeignKey("RelatedBillID")] 
    public virtual Bill RelatedBill { get; set; } 

    public RelationshipWrapper Relationship { get; set; } 

    ... 
} 

我在各種各樣的化身只有試過,通過模型構建器上的DbContext和使用都明確定義的關係數據的註釋,但是上面的定義是什麼我要找的。我正在使用集合,因爲外鍵屬性不是主鍵。

使用此設置我得到一個錯誤:Bill_ID column is not defined(或類似的東西)。

如果我使用以下代碼獲取了模型構建器路線,則會出現「表格BillRelations在數據庫中不存在」的錯誤。

modelBuilder.Entity<Bill>().HasMany(b => b.RelatedBills) 
          .WithRequired(r => r.Bill) 
          .Map(m => m.MapKey("BillID").ToTable("BillRelations")); 
modelBuilder.Entity<BillRelation>().HasRequired(r => r.RelatedBill) 
            .WithRequiredDependent() 
            .Map(m => m.MapKey("RemoteBillID").ToTable("BillRelations")); 

我已經能夠使其通過定義只有關係的一個半上班,票據 - > BillRelations,然後用我的存儲庫中的加入填補上BillRelations類的[NotMapped] RelatedBill財產爲每條例草案的相關條例草案收集中的相關條例草案。如果我能幫上忙,我寧願不這樣做。

我想過的唯一的其他解決方案是在一個單獨的表格(有4種類型)中對每個關係進行建模,並使用標準Bill < - >通過每種關係類型的連接表進行Bill映射 - - 如果我能避免,我寧願不這樣做。

任何人都可以看到我在做什麼錯誤或告訴我,如果我想要做什麼甚至可能在EF代碼優先4.1?

回答

2

只是一些想法:

  • 您與數據註解映射不起作用,因爲EF代碼優先約定不承認其導航性能是一起的。顯然你想聯繫Bill.RelatedBillsBillRelation.Bill。但是由於第二個導航屬性BillRelation.RelatedBill指的是Bill實體,因此AssociationInverseDiscoveryConvention不能用於識別正確的關係。此慣例僅適用於實體上只有一對導航屬性的情況。因此,EF實際上假定了三種關係,每種關係在模型中只有一個暴露的末端。 Bill.RelatedBills所屬的關係根據EF默認的命名約定假設在另一端沒有公開的外鍵 - 它是帶有下劃線的Bill_ID。它不存在於數據庫中,因此是例外。

  • 在你的Fluent API映射中,我只是試圖完全刪除...ToTable(...)。我認爲這是沒有必要的,因爲映射無論如何都知道外鍵屬於哪個表。這可能會修復第二個錯誤(「表...不存在....「)

  • 您的第二個映射 - 一對一關係 - 可能無法按預期工作,因爲一對一關係通常與數據庫中的表之間的共享主鍵關聯映射。 (我不確定,如果EF真的需要共享主鍵。)因爲你的BillId列似乎是一個外鍵,它不是同時的主鍵,所以我會嘗試將關係映射爲一對多而且因爲你的外鍵列被暴露爲模型的屬性,你應該使用HasForeignKey而不是MapKey

    modelBuilder.Entity<Bill>() 
        .HasMany(b => b.RelatedBills) 
        .WithRequired(r => r.Bill) 
        .HasForeignKey (r => r.BillID); 
    // turn off/on cascade delete by chaining 
    // .WillCascadeOnDelete(true/false) 
    // here at the end 
    
    modelBuilder.Entity<BillRelation>() 
        .HasRequired(r => r.RelatedBill) 
        .WithMany() 
        .HasForeignKey (r => r.RelatedBillID); 
    // turn off/on cascade delete by chaining 
    // .WillCascadeOnDelete(true/false) 
    // here at the end 
    

編輯

這是可能的,如果你把[InverseProperty]屬性上的導航性能的一個整體流利的映射是沒有必要的 - 例如,在您的Bill類:

[InverseProperty("Bill")] 
public virtual ICollection<BillRelation> RelatedBills { get; set; } 

在這屬性,您可以指定相關實體上的關聯導航屬性的名稱。這將Bill.RelatedBillsBillRelation.Bill一起綁定到作爲相同關聯的結尾的一對導航屬性。我希望EF會對剩餘的導航屬性BillRelation.RelatedBill做正確的事情,即創建一對多的關係 - 我希望...如果默認的級聯刪除不適合你,你不得不使用Fluent API儘管由於沒有數據註釋屬性來配置級聯刪除。