2012-06-08 44 views
2

我知道這個問題上有很多問題,但我沒有設法找到一個實際解釋如何解決我的問題特別的問題。我想這意味着它可能不可能解決(我認爲這可能是EF的思維方式「倒退」),但我必須問。用Code First定義實體框架中的一對一或零關係

我有三個(略)波蘇斯模型像這樣:

[Table("People")] 
public class Person { 
    public int PersonID { get; set; } 
    [Required] 
    public string PersonName { get; set; } 
} 

public class Location { 
    public int LocationID { get; set; } 
    public int LocationTypeID { get; set; } 
    public virtual LocationType LocationType { get; set; } 
} 

public class Van : Location { 
    public int PartyID { get; set; } 
    public virtual Party Party { get; set; } 
} 

這些由(略)數據庫表支持(我們寫這些手工):

CREATE TABLE People (
    PersonID INTEGER IDENTITY NOT NULL, 
    PersonName VARCHAR(255) NOT NULL, 
    PRIMARY KEY (PersonID) 
) 

CREATE TABLE Locations (
    LocationID INTEGER IDENTITY NOT NULL, 
    LocationTypeID INTEGER NOT NULL, 
    FOREIGN KEY (LocationTypeID) REFERENCES LocationTypes(LocationTypeID) 
) 

CREATE TABLE Vans (
    LocationID INTEGER NOT NULL, 
    PersonID INTEGER NOT NULL, 
    PRIMARY KEY (LocationID), 
    FOREIGN KEY (LocationID) REFERENCES Locations(LocationID), 
    FOREIGN KEY (PersonID) REFERENCES People(PersonID) 
) 

你可以大概想象一下LocationTypes的樣子。

Locations是每個表類型的層次結構的根目錄 - 也有檢查約束來執行此操作。 Vans是一種位置,因爲其他東西無關像Warehouse。現在

,一個Van屬於Person,在我們發出了一輛麪包車到員工,它是他們的責任與燃料填滿它,不會崩潰,它需要客戶的網站時,他們已經爲了更多的東西用完了所有的螺絲,鑽頭和鎧裝直流電纜。然而,並非每個Person都有一輛貨車(其中一些在一輛貨車中成對運行),而Person表沒有指向Van的外鍵 - 反過來也是如此。這在某種意義上是歷史事故,但它對整個情況非常整潔地模擬,因爲雖然Person不必具有Van,但最確定地必須有一個人。

所以對我的問題:我如何得到Person導航屬性與他們的Van它?

public virtual Van Van { get; set; } 

我所做的與數據註釋和流暢的API玩弄了很多,我已經得到了最接近的是這OnModelCreating

modelBuilder.Entity<Van>() 
    .HasRequired(v => v.Person) 
    .WithOptional(p => p.Van); 

可惜這試圖填充Van屬性與代理產生一個Location對象。它甚至可能是正確的Location對象(我無法檢查),但它沒有意識到它應該在尋找貨車。然而,我懷疑它可能試圖匹配PersonIDLocationID,當它進行查找時 - 沒有Fluent API映射,我根本沒有任何麪包車,這是我所期望的(所有PersonID值都低於與貨車對應的最低LocationID值,所以無法找到任何東西)。

這無疑將是很容易的,如果Person有一個空的外鍵Van,但後來我們不得不在兩個方向上的外鍵,如果我們拿了一個出來的Van那麼我們就無法建模絕對必要的約束,即Van有一個Person

所以,我認爲,Van擁有這種關係,並Van財產上Person是逆導航屬性,但它似乎EF是不是在這個把戲的一個對的人,即使一端非常好是可選的。有沒有辦法讓它工作,還是我必須接受妥協?

爲了實體框架的缺失特性,我們通常拒絕妥協數據庫模型。我真正需要的是一種告訴EF的方式,Person上的Van屬性可以通過加入Vans上的Vans on Vans.PersonID = Person.PersonID來填充。

回答

4

問題是,這是目前不支持。你提到你沒有設法找到任何問題將解決你的問題。我不知道你是否發現任何問題提及EF不支持解決這種類型的一對一關係所必需的唯一約束/候選鍵。

只有在從屬表中的FK是唯一的時,才能實現數據庫中的一對一關係。這可以通過兩種方式完成:在依賴表中將FK列放置唯一約束(索引)或在依賴表中使用PK作爲FK到主表。

EF執行與數據庫相同的參照完整性規則,但在一對一關係的情況下,並且缺乏對唯一約束的支持,它不支持前一種方式。 EF可以通過僅使用從屬表的PK作爲FK到主表來模擬一對一關係。

您可以投票支持Data UserVoice上的唯一約束/候選鍵。

如何解決您的特定問題?通過欺騙EF。讓EF認爲你有一對多的關係,並在PersonIDVan表中設置唯一約束。比起更新您的人是這樣的:

[Table("People")] 
public class Person { 
    public int PersonID { get; set; } 
    [Required] 
    public string PersonName { get; set; } 

    public virtual ICollection<Van> Vans { get; set; } 

    [NotMapped] 
    public Van Van 
    { 
     get { return Vans.FirstOrDefault(); } 
     set 
     { 
      Vans.Clear(); 
      if (value != null) 
      { 
       Vans.Add(value); 
      } 
     } 
    } 
} 

這是很醜陋的解決方法,因爲Vans收集仍然是公衆。你可以用它的知名度發揮,但要確保你明白幾件事情:

  • 一旦Vans是不公開的,你必須在OnModelCreating映射,併爲這方面必須能夠看到的財產,或者你必須提供映射配置哪些呢那。有關更多信息,請檢查thisthis
  • Vans屬性不能打破的規則創建代理支持懶加載
  • 預先加載必須使用Vans財產
+0

我希望情況並非如此,但這是我最終發佈後實施的解決方案這個問題只是讓我們能夠得到它的工作。至少數據庫知道發生了什麼! –

相關問題