2012-02-23 101 views
1

我使用EF與TPC和我有多重繼承可以說我有實體框架TPC多重繼承

員工(摘要)

開發者(從僱員繼承)

SeniorDeveloper(繼承來自Developer)

我在數據庫中插入了一些行,EF正確地讀取它們。

但是 當我插入新的SeniorDeveloper時,將值寫入SeniorDeveloper AND Developer數據庫表,因此查詢開發人員(context.Employees.OfType())也會獲得最近添加的SeniorDevelopers。

有沒有辦法告訴EF,它應該只存儲在一張表中,還是EF爲什麼會回退到TPT策略?

+0

這兩個問題是不相關的。你確定數據真的在'Developers' table =你確定你已經正確配置了TPC嗎? 'OfType'的問題與TPC/TPT無關。這就是'OfType'的工作原理。 – 2012-02-23 10:11:33

+0

OfType確實在tpt ... 中的工作方式,我將每手的值插入到數據庫(開發人員開發人員和高級開發人員僅限高級開發人員),OfType ()只給我開發人員,沒有高級開發人員聽起來有點奇怪。 我設置了所有像這裏所說的http://cockneycoder.wordpress.com/2010/11/25/entity-framework-and-concrete-table-per-type-in​​heritance/ – relascope 2012-02-24 10:31:43

回答

1

由於它看起來並不像EF支持與TPC的多重繼承,我們最後使用的員工TPC來開發和SeniorDeveloper之間開發和TPT ......

+0

EF不正確, t支持與TPC的多重繼承。對於EF> = 4.1它起作用(類型上的'OfType'只是簡單地將這個類型的表和所有派生類型翻譯成SQL中的UNION。 INSERTS只能插入所插入類型的表格中,而不能插入任何基本類型的表格中。由於EF 4.1使用EF 4.0的ObjectContext,我也懷疑它在EF 4.0中不受支持。 – Slauma 2012-05-24 15:51:54

1

我相信這是一個原因,儘管我可能看不到完整的畫面,可能只是猜測。

情況

事實上,唯一的方法(我見)EF能夠通過只讀取僅列出非高級開發人員(您的查詢用例)的TPT方案爲Developer表將使用鑑別器,並且我們知道EF不使用TPT/TPC策略中的一個。

爲什麼?那麼請記住,所有高級開發人員都是開發人員,因此他們只有一個Developer記錄以及一個SeniorDeveloper記錄是很自然的(也是必要的)。

唯一的例外是,如果Developer是抽象類型,在這種情況下,您可以使用TPC策略來刪除Developer表。然而在你的情況下,Developer是具體的。

目前的解決方案

記住這一點,並沒有在Developer表鑑別,只有這樣,才能確定是否有任何開發商是一個非高級開發人員是通過檢查,如果它是一高級開發者;換句話說,通過驗證在SeniorDeveloper表或任何其他子類型表中沒有開發人員的記錄。

這聽起來有點明顯,但現在我們明白了爲什麼當它的基本類型(開發人員)具體(非抽象)時,必須使用和訪問SeniorDeveloper表。

當前實現

我從記憶寫這個,所以我希望這不是太掉,而這也是什麼Slauma在另一則留言中提到。你可能想要啓動一個SQL分析器並驗證它。

它的實施方式是通過請求表的預測的聯合。這些投影只是添加一個鑑別器,以某種編碼方式聲明他們自己的類型[1]。在聯合集合中,行可以根據這個鑑別器進行過濾。

[1]如果我沒有記錯,它就像這樣:0X爲基本類型,0X0X爲聯合中的第一個子類型,0X1X爲第二個子類型,依此類推。

權衡#1

我們已經可以識別一個權衡:EF可以存儲鑑別表中,或在「運行時」可以「產生一個」。

  • 存儲的鑑別器的缺點是它的空間利用率較低,並且可能「醜陋」(如果這是一個參數)。優點是查詢性能在一個非常特殊的情況下(我們只想要基地類型的記錄)。
  • 「運行時間」鑑別器的缺點是查找性能不如同樣的用例。優點是它更節省空間。

乍一看,似乎有時我們可能更願意爲查詢性能交易一點點空間,而EF不會讓我們這樣做。

實際上,它並不總是清楚什麼時候;通過請求兩個表的UNION,我們只查找兩個索引而不是一個索引,性能差異可以忽略不計。使用單一級別的繼承,它不會比2倍差(因爲所有子類型集合都是不相交的)。但是,等等,還有更多。

權衡#2

請記住,我說的是存儲,鑑別方法的性能優勢將只出現在特定的使用情況,我們查找的基本類型的記錄。這是爲什麼?那麼,如果你正在尋找可能是或可能不是高級開發者[2]的開發者,那麼你不得不查找SeniorDeveloper。雖然這一點看起來很明顯,但可能不那麼明顯的是,EF無法預先知道這些類型是否只屬於某種類型。這意味着在最壞的情況下,它必須發出兩個查詢:Developer表中有一個,如果結果集中有一個高級開發人員,則在SeniorDeveloper表中有第二個。

不幸的是,額外的往返可能具有比兩個表的工會更大性能的影響。 (我可能說,我沒有驗證它。)更糟糕的是,它增加了每個在結果集中有一行的子類型。想象一下有3種,5種甚至10種亞型的類型。

這就是你的權衡#2。

[2]請記住,這種操作可能來自應用程序的任何部分,而解決折衷必須在全局範圍內完成以滿足所有進程/應用程序/用戶。此外夫婦,與事實EF團隊必須做出這些權衡所有的EF用戶(雖然這是事實,他們可以添加一些配置爲這些類型的取捨)。

另一種可能

通過批量SQL查詢,將有可能避免多次往返。 EF將不得不向服務器發送一些過程邏輯以進行條件查找(T-SQL)。但由於我們已經建立在權衡#1的性能優勢是最有可能可以忽略不計在許多情況下,我不知道這將永遠是值得的。也許有人可以爲此打開問題單以確定它是否有意義。

結論

在未來,也許有人可以與一些有創意的解決方案,這種特定情況下優化了幾個典型的操作,然後提供一些配置交換機時,優化涉及這樣的取捨。

眼下不過,我認爲EF已經選擇了一個公平的解決方案。以一種奇怪的方式,它幾乎更乾淨。

的幾個注意事項

  • 我認爲使用工會的是在某些情況下應用的優化。在其他情況下,它將是一個外連接,但使用鑑別符(和其他所有內容)保持不變。

  • 你提到的多重繼承,這有點糊塗了最初。在通用的面向對象的說法中,多繼承是一種類型有多種基類型的構造。許多面向對象的類型系統不支持它,包括CTS(由所有.NET語言使用)。你的意思是在這裏。

  • 您也提到,EF將「回退」到TPT策略。在Developer/SeniorDeveloper的情況下,TPC策略與TPT策略的結果相同,因爲Developer是具體的。如果你真的想要一個表,你必須使用TPH策略。

+0

+1爲您的偉大工作!無論如何,我還沒有參加過這個項目(並在SO上)一段時間,所以我現在就讀了它。很好解釋! (沒有驗證) – relascope 2015-04-17 21:08:49