2016-04-08 61 views
5

我有一個問題,我認爲很多專業開發人員會遇到這個問題。我的工作場所採用了實體框架。我們使用它,並且喜歡它。但是,我們似乎遇到了一個非常令人沮喪的侷限。實體框架 - 高效的渴望加載與依賴對象的長鏈?

讓我們假設你有一個對象鏈等

甲 - >乙 - 「ç - > d

我們專業,所以這些對象有大量的數據,而且有很多的他們在他們各自的數據庫表中。看起來EF有一個可怕的時間加載任何超過對象B的東西。它生成的SQL查詢效率並不高。呼叫會像

context.objects.include("bObjectName.cObjectName.dObjectName").FirstOrDefault(x => x.PK == somePK); 

我們已經明確地加載對象過去與.Load()命令第二級解決此得到。這適用於單個對象。但是,當我們談論對象集合時,我們開始遇到與.Load()相關的問題。

首先,有沒有似乎是保留對象的代理跟蹤集合中沒有虛擬關鍵字的方式。這很有意義,因爲它需要覆蓋get和set函數。但是,這會啓用延遲加載,並且.Load()在啓用延遲加載時不會映射實體。我覺得自己有點奇怪。如果刪除虛擬關鍵字,.Load()會自動將加載的對象鏈接到上下文中的相關對象。

因此,這裏是我的問題的癥結所在。我想要代理跟蹤,但也想.Load()爲我導航的屬性。如果EF可以產生好的查詢,這些都不是問題。我明白爲什麼它不能,它必須是一個適合所有類型的東西。

所以加載對象的二三線我也許可以在我的服務層裝載函數,它接受對象的第二層的所有主鍵,然後再對它們調用.Load()。 有沒有人有這個解決方案?好像EF7,或Core 1.0解決了這個:

  1. 徹底消除延遲加載,我們可以關掉爲好,但它會破壞很多舊的代碼。
  2. 添加新的「ThenInclude」功能,據稱提高鏈接的效率大量包括。

如果關閉延遲加載是答案,那很好,我只是想在耗費大量時間重新開發一個巨大的webapps價值的服務調用之前耗盡所有選項。 有沒有人有任何想法?我願意投入一切。我們正在使用EF6。

編輯:它似乎答案是關閉延遲加載在上下文級別,或升級到EF7。如果其他人設法找到一種解決方案,我可以改變這種情況,您可以通過強制加載EF6單個對象進行代理跟蹤。

+0

您是否運行SQL事件探查器來查看實際的SQL查詢是什麼? – Ellesedil

+0

是的,我可以告訴你,從字面上看,無論何時您鏈接到第三級,查詢都會非常低效。這是因爲這些查詢是程序化生成的,所以這是可以理解的。可以理解,它不適用於專業級軟件。 一個解決方案是腳趾保存.Load()的結果並手動將其設置爲正確的對象。所以在這種情況下,加載所有的C並將它們設置爲B,但是這裏的所有開發人員都同意,我們不喜歡這樣。 我們喜歡當虛擬被移除時的功能,但我們也希望代理跟蹤,因此我們可以添加到對象B中的icollection。 – Gaugeforever

+0

據我所知,您可以添加第三點到EF 7的優勢。它最終實現了批量查詢,這意味着它可以將單個調用中的許多查詢捆綁到SQL中。這應該允許它對依賴實體發出不同的查詢,同時還會導致對SQL的單個調用,而不是之前發出的可怕單個查詢。對於延遲加載的性能問題,由於缺少批量延遲加載功能,這是EF特定的問題。請參閱[這裏用NHibernate的解釋](/ a/36070727/1178314)。你的情況將會改變遊戲規則。 –

回答

1

對鏈接.Include()語句,the performance documentation發出警告表示每個鏈接的鏈接超過3個.Include()將添加外部聯接或聯合。我不知道ThenInclude,但它聽起來像一個gamechanger!

如果你把你的虛擬導航性能,但關閉延遲加載上的DbContext

context.ObjectContext().ContextOptions.LazyLoadingEnabled = false; 

然後(只要更改跟蹤已啓用),您可以執行以下操作:

var a = context.aObjectNames.First(x=> x.id == whatever); 

context.bObjectNames.Where(x=> x.aId == a.Id).Load() 

這應填充a.bObjects

+0

我們希望保留所有舊代碼的延遲加載。看來這是不可能的。延遲加載和更改跟蹤緊密結合在一起。這對我來說很奇怪,因爲我想不出他們應該是什麼原因。 刪除延遲加載涉及更改很多舊的(讀取:錯誤)代碼。這應該做反正,但時間......錢....等 我將這標記爲答案,因爲沒有人給EF6更好的一個。 – Gaugeforever

+0

您可以在不關閉上下文的延遲加載的情況下進行加載。導航屬性僅在您訪問它們時加載,因此您可以提前進行加載以避免在訪問屬性時進行延遲加載。這實際上取決於你的用例,但延遲加載本質上並不壞,如果你只使用了B或C中的一些屬性,那麼延遲加載它們可能是有意義的,而不是拉回整個對象。顯然,如果你迭代一個集合,懶惰加載不是你的朋友,因爲你最終會遇到n + 1問題。 –

+0

對,您可以在啓用延遲加載的情況下加載上下文。但是,長鏈收集會產生可怕的查詢,並且數據量很大。 這是一個問題,我懷疑它只會在專業軟件開發中出現,因爲它有其獨特的限制。我們進入「做這個」,「但是這個」等循環論點。等等。 EF7的「ThenInclude」功能解決了這個問題,但是它們消除了延遲加載。所以,是啊... 基本上,我需要加載,啓用延遲加載,更改跟蹤,所以我可以使用.Load()具有EF自動連接對象。 – Gaugeforever

相關問題