前一篇文章 在 LINQ 裡使用 Left Join 還有哪些需要注意的呢? 中,筆者概括的介紹了在 LINQ 中,使用 LEFT JOIN 與多條件的使用方式,以及需要注意的地方。今天筆者在撰寫程式時又發現一個有趣的地方,就是當使用EDM時,多條件的 JOIN 當中,如果條件有些是 Nullable
前一篇文章 在 LINQ 裡使用 Left Join 還有哪些需要注意的呢? 中,筆者概括的介紹了在 LINQ 中,使用 LEFT JOIN 與多條件的使用方式,以及需要注意的地方。今天筆者在撰寫程式時又發現一個有趣的地方,就是當使用EDM時,多條件的 JOIN 當中,如果條件有些是 Nullable<T>,也就是在資料庫中是可允許 null 的欄位該怎麼辦呢?這時你應該會得到像下面這樣的錯誤:
有時我們會很直覺的將程式改為如下:
1: from tran in m.DefaultIfEmpty() where tran!=null join item in VirusChange_RGHeight_Items
2: on new {RGHeightID=tran.RGHeightID.HasValue?tran.RGHeightID.Value:0, Pathogen_ID=tran.Pathogen_ID.HasValue?tran.Pathogen_ID.Value:0} equals new {item.Parent_ID, item.Pathogen_ID} into mm
又或者式改為如下:
1: from tran in m.DefaultIfEmpty() where tran!=null join item in VirusChange_RGHeight_Items
2: on new {tran.RGHeightID,tran.Pathogen_ID} equals new {RGHeightID=item.Parent_ID.GetValueOrDefault(0), Pathogen_ID=item.Pathogen_ID.GetValueOrDefault(0)} into mm
不過,很遺憾的,還是不行……
其時一樣回歸到 C# 的 CLR 平台上對於型別的要求是非常嚴謹的,雖然 LINQ 在這裡有自動型別推斷的機制,你想想看,int? 與 int 直接比較是非常不嚴警的做法。因此到最後可以可以用的版本是如下:
1: from tran in m.DefaultIfEmpty() where tran!=null join item in VirusChange_RGHeight_Items
2: on new {tran.RGHeightID,tran.Pathogen_ID} equals new {RGHeightID=(int?)item.Parent_ID, Pathogen_ID=(int?)item.Pathogen_ID} into mm
如同在 LINQ 的 Where 條件式裡使用 ToString() 一樣,在 LINQ to Entities 裡面它必須對應到一個 .NET 的CLR 的一個實體,必須經由這個實體轉換為 SQL 語句,而且在 LINQ to Entities 中的查詢條件是使用 IQueryable<T>,而在裡面下的標準函式會轉譯成所使用之 (提供者資料庫) 的正確對應存放函式。 這樣就可以真的達到跨資料來源的型式。簡單的說,就是它必須是可以直接被轉換為目的資料庫的 SQL 語句的。可是呢!為了在不同的資料庫、來源,提供一致的查詢方式。因此在 LINQ to Entities 裡面如果使用了一些無法明確對映到基礎資料來源的 CLR 方法,就會得到一個 NotSupportedException 的例外。
結語:
剛開始或許會覺得奇怪,想不明白,其實這是因為在 LINQ to Entities 這裡較 LINQ to SQL 來的嚴謹。它未來會支援多種類的資料庫。我想在這個部份也不能這麼鬆散。
參考資料:
CLR Method to Canonical Function Mapping
http://msdn.microsoft.com/en-us/library/bb738681.aspx
Workarounds for using custom methods/extension methods in LINQ to Entities
標準函式 (Entity SQL)
http://msdn.microsoft.com/zh-tw/library/bb738626.aspx
MSDN 論壇 (LINQ to Entities does not recognize the method 'System.String ToString()' method)
LINQ to Entities 中的已知問題和考量因素
http://msdn.microsoft.com/zh-tw/library/bb896317.aspx#TypeConversionErrors
簽名:
學習是一趟奇妙的旅程
這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。
軟體開發之路(FB 社團):https://www.facebook.com/groups/361804473860062/
Gelis 程式設計訓練營(粉絲團):https://www.facebook.com/gelis.dev.learning/
如果文章對您有用,幫我點一下讚,或是點一下『我要推薦』,這會讓我更有動力的為各位讀者撰寫下一篇文章。
非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^