2011-08-24 102 views
13

我有兩個相關的實體,但傳統sql模式基本上有兩個同一個表的關鍵列(不是2列鍵:見下文)。我需要創建一個關係到'人造鑰匙'列。有沒有辦法在Entity Framework 4.1中聲明性地做到這一點?實體框架4.1 - 非關鍵列之間的關係

Public Class Client 
    Inherits ModelBase 

    <Key(), Required()> 
    Public Property ClientID As Decimal 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 


Public Class ClientLocation 
    Inherits ModelBase 

    ........ 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 

    <ForeignKey("ClientCode")> 
    Public Overridable Property Client As Clients.Client 

而且我得到的錯誤是:模型生成過程中檢測到

*一個或多個驗證錯誤: System.Data.Edm.EdmAssociationConstraint:在類型所有 屬性參照約束的相關角色必須爲 ,與主體角色中相應的屬性類型相同。 類型的特性「ClientCode」對實體「ClientLocation」不 匹配屬性的類型在 引用約束「ClientLocation_Client」對實體「客戶」「客戶端ID」。*

,因爲它認爲我」米試圖映射ClientLocation.ClientCode> Client.ClientID,當我真的試圖映射ClientLocation.ClientCode> Client.ClientCode ...

有什麼想法?

謝謝!

+0

「* ...傳統sql模式本質上具有2個相同表的鍵列... *」:你的意思是'Client.ClientCode'是一個在數據庫中具有唯一索引的列嗎?或者,那麼「2個關鍵列......但不是組合鍵」?並且你想將'ClientLocation.Client'映射到這個獨特的列'Client.ClientCode'? – Slauma

+0

該表有2個有效密鑰,但第二個不被識別爲密鑰,並且沒有索引。例如,ClientID可以是4,並且ClientCode可以是「FOGCREEK」。兩者不相關或不相關,它們恰好都是獨一無二的。 是的,我需要使用Client.ClientCode映射回原始表,即使它未在我的實體中標記爲鍵。 –

+0

啊,我明白了,那麼'ClientCode'就是一個普通的列。業務邏輯偶然確保了唯一性。恐怕Ladilav的回答是最後的話。 – Slauma

回答

3

實體框架要求在主表中的整個主鍵和相應的列(外鍵)之間建立關係,將它與依賴表建立在一起。

+0

那麼通過你的理解,沒有辦法像我們可以「映射」表和列名一樣來「映射」關係? –

+0

您必須像在數據庫中一樣映射關係。如果您的數據庫沒有正確設置表,則EF無法修復它。 –

+1

儘管這個答案可能是對的,但我不願意接受它,但沒有更多的共識。任何人都可以證實沒有類似於Data Annotations 的方法來幫助覆蓋關係字段嗎? –

0

(這僅是一個附錄,拉吉斯拉夫的回答,接受並賞金不能去我的回答。)

我會感到驚訝,如果這樣的功能將永遠在EF來實現。爲什麼?因爲你甚至不能在關係數據庫中創建這樣的關係。關係數據庫中的外鍵關係(至少是SQL Server,可能是大多數或所有其他數據庫)要求主方是主鍵或具有唯一鍵約束的列。這是有道理的,因爲外鍵應該指主表中的一個唯一行

現在,EF甚至不支持與唯一鍵列的關係,而只支持主鍵列。這是未來可能會受到支持的事情。但支持外鍵關係到非唯一和非主鍵列對我來說似乎沒有意義。

如果主體表的目標列中的值不唯一,您預期會發生什麼?你是否想要例外 - 例如 - 嘗試急切加載ClientLocation.Client - 「由於外鍵沒有引用唯一目標」或警告「無法加載導航屬性'客戶端'」加載客戶端但在那裏是另一個,不能確保我加載了你想要的那個「或類似的東西?

如果你想幫自己一個忙,我會放棄這個想法,刪除導航屬性,並認爲在你的LINQ查詢中與Join一起工作很多。

0

可能的關聯屬性是你的答案,使用關聯你可以指定在關係的每一邊使用哪些關鍵字。

一些這樣的代碼:

[ForeignKey()] 
[Association("SomeNameForAssociation","TheKeyInThisEntity","TheKeyOnTheAssociationTargetEntity")] 
public virtual Examination Examination { get; set; } 

如果我明白你的問題,你的代碼應該改爲:

Public Class Client 
    Inherits ModelBase 

    <Key(), Required()> 
    Public Property ClientID As Decimal 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 


Public Class ClientLocation 
    Inherits ModelBase 

    ........ 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 

    <ForeignKey("ClientCode")> 
    <Association("ClientClientCodes","ClientCode","ClientCode")> 
    Public Overridable Property Client As Clients.Client 

第一 「ClientCode」:在ClientCode鍵列的名稱。 第二個「ClientCode」:您要使用的ClientCode中的鍵列名稱。

注意:我還沒有使用這個屬性,但它的文檔,它的名字和它的參數名稱表明它應該滿足你的需要。

+0

我懷疑'[Association]'屬性在實體框架中有什麼作用。它只是LINQ to SQL的映射屬性。 – Slauma

2

即使這是不可能的,你仍然可以使用LINQ查詢(C#)(請參閱此question)來加入這兩個表。

var result = from a in ctx.Client 
      join b in ctx.ClientLocation 
      on a.ClientCode equals b.ClientCode 
      select new { Client = a, Location = b }; 

您只是缺少導航屬性Client.ClientLocation和ClientLocation.Client。這樣做更麻煩一些,但是可能。

如果您願意擴展SQL方案,則可以添加另一個表,如ClientLocationClient,它充當M:N表,其中外鍵用於Client和ClientLocation,兩者用作組合鍵。然後,您可以瀏覽像這樣(C#)

var client = myClientLocation.ClientLocationClients.First().Client; // there's only one 

這一行,但是隻要你有沒有相應的客戶端,當然你需要在客戶端定義一個觸發同步您的分機表ClientLocation失敗並配置刪除級聯和ClientLocation需要插入客戶端之前,否則觸發器將失敗......總的來說,我只是想說出一個警告,這可能是一個相當危險的路線。