2014年5月15日 星期四

Entity Framework 與 LINQ -- 篩選(Where)使用時機

最近發現,使用Entity Framework的話,要注意下Where的時機,因為有可能是會在SQL端篩選,也有可能會在C#端篩選,可能會導致不同的結果,甚至發生不支援的情況。

拿字串A是否包含了字串B作為範例,這時候在SQL端(還沒產生成實體物件)時執行結果 跟 C#端(已從DB撈出資料)執行結果 就會發生不同的狀況。
先來看一Where下在資料還沒產生成實體物件的時候
C#:
var query = db.Table.Where(x => x.Name.Contains("abc")).ToList();
SQL執行語法會是
SELECT[EmployeeId],[Name]
FROM [dbo].[Employee]
WHERE [Name] LIKE '%abc%'
由此可見,資料判斷是在SQL端處理,然後把結果丟回到C#端。

再來是Where下在ToList()後面
C#:
var query = db.Table.ToList().Where(x => x.Name.Contains("abc"));
SQL執行語法會是
SELECT[EmployeeId],[Name]
FROM [dbo].[Employee]
這時候變成了把所有Employee資料撈出來以後,在篩選資料。

一個是在SQL端下LIKE,一個是在C#端執行Contains,都是包含"abc",但是結果就會不一樣囉。

SQL的LIKE是不分辨大小寫的,所以"ABC"、"AbC"、"abc"、"abC"...都是會被認為是OK的資料。
但是在C#的Contains是有區分大小寫的,所以只有"abc"才會被篩選出來。

如果使用IndexOf去指定不區分大小寫,但是這個只能在C#端使用
錯誤的C#語法:
var query = db.Table.Where(x => x.Name.IndexOf("abc", StringComparison.CurrentCultureIgnoreCase) >= 0).ToList();
這樣會報錯,因為LINQ在轉SQL語法的時候會發生不支援的情況,就回歸到一開始提到的Where時機。
所以我們要在取出資料後,由C#去執行篩選
C#語法:
var query = db.Table.ToList().Where(x => x.Name.IndexOf("abc", StringComparison.CurrentCultureIgnoreCase) >= 0);

PS:Contains是使用IndexOf去實做出來的,所以基本上IndexOf效能會略好於Contains



沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...