C# - LINQ to Entities Part I

.Net提供了Entity Framework與LINQ的技術,讓Programmer能夠更快速簡單的操作集合類型的資料(例如:資料庫, 陣列…等),LINQ提供Programmer可以直接在程式中對資料集合撰寫類似SQL語法的描述以篩選資料,但這種類SQL語法實在是太冗長,對Programmer來說會不太習慣。因此.Net Framework將常用的SQL操作包裝成Function,讓Programmer能夠更簡單的使用。



Enumerable為LINQ to Entities支援LINQ查詢的Extention Class,實作許多IEnumerable<T>擴充功能的,主要提供IEnumerable<T> LINQ to Entity的功能,讓Programmer使用Lambda語法輕鬆的對IEnumerable<T>集合資料進行SQL條件的操作,例如:Select, Where, Distinct…等,當然也有非SQL的操作,例如一些針對集合內的每筆資料的操作(ForEach),另一點好處在於LINQ to Entities可以透過連續串接查詢的Function來完成一連串條件的篩選,稱之為命令樹查詢,以下限量將分成好幾篇來簡單介紹Enumerable中LINQ to Entities的好用功能,首先介紹幾個跟查詢有關的Extention方法:

  1. Select
  2. SelectMany
  3. Where
  4. Distinct
  5. GroupBy
  6. OrderBy & OrderByDescending
  7. Any
  8. Join

為了更方便介紹上述的幾個Function,限量用SQLite資料庫簡單的建了兩個Table,在範例中會使用這些Function來篩選DB的資料,另外,限量用LINQPad這款奧步工具,這工具可以把最頭痛的LINQ to Entities邏輯轉換成SQL語法,利用這個功能就能夠Check執行的SQL是否和你想像的一樣,真是忍不住要讚一下。
以下為範例的兩個Table為以一個簡單的購物網站為前提下所設計的,當然是會非常陽春,User(會員) and Good(商品資訊):






Select

Select就是SQL的SELECT語法,但會選取集合中每筆資料的指定欄位值,組成新的集合,
使用方式如下:

Scenario:

在User Table裡挑出所有欄位Name的值,Lambda表示式裡,u代表的是User Table的單筆資料,u.Name為單筆資料的Name屬性(DB裡Name欄位,因為使用Entity Framework,DB裡的欄位已轉為Object的屬性)。



Result:


SQL:



執行完後可以發現結果為Query<String>的集合型別。
從上面範例看來,許多人會以為Select只能針對單一集合進行操作,這個想法就錯了,其實Select可以同時Select其他Table的資料組合成新的Table,追根究底,Select本質就是將欄位值取出來後組成新的Table,範例如下:


Scenario:

取得User Table裡的Name值作為新欄位User,並在Good裡取得SalesID與User ID的資料作為新欄位Good,new代表要產生一個新的table,new區間裡放的是指定的欄位名稱與條件篩選。


Result:

SQL:


從結果可以看到這個結果Table有兩個欄位,User欄位存放User Table的Name欄位值,Good欄位存放Good Table裡,與該User有關的資料,這個Table可以視為一個Dictionary,Key為User,Value為List<Good>。


SelectMany

SelectMany與Select是一樣的操作,但不同的是SelectMany會將Select出的物件視為只有一層的集合。

Scenario:

將Good Table資料依SalesID Group起來再選取。

Result:

SQL:




這樣看好像看不出什麼,那我們以同樣的Scenario來與Select比較看看會發生什麼結果。

Scenario:



Result:


SQL:


這兩個結果比較之後,可以發現,用Select的結果會多包了一層,結果呈現會以Dictionary的方式,一個Key值對應多筆資料,而SelectMany則會將每筆資料視為同一層,從兩邊的SQL語法也可以發現,SelectMany用INNER JOIN的方式將資料整合在一起,而Select則使用多次的Select語法,分別Select出符合的資料。


Where

Where就是SQL語法中的WHERE條件式,與Select不同的是,Where是基於原集合資料去搜尋符合條件的資料,不會產生新的集合。

Scenario:

從Good Table裡取出所有SalesID為2的資料行。


Result:

SQL:




Distinct

Distinct為SQL語法中的DISTINCT操作,區分集合中每種獨特的欄位值,這裡要注意的是Distinct只適用於當集合裡的每筆資料只有單一欄位時,例如List<String>,因為Distinct沒有其他傳入參數的多載,所以如果集合有多個Column時就要搭配Select。


Scenario:

先使用Select將Good Table的SalesID選取出來,在使用Distinct將重複的SalesID值去除。

Result:

SQL:


GroupBy

GroupBy為SQL語法的GROUPBY操作,根據所指定的欄位值進行Group的動作,通常GroupBy會和Distinct拿來做比較,如果單純只想知道某個欄位有哪些值,只要用Distinct就可以了,GroupBy通常Group後,再用來進行一些Sub-query的動作。


Scenario:

將Good Table的資料依據SalesID Group起來。

Result:


Result:


從結果可以看到,GroupBy完,結果會是一個Dictionary的型態,Key為SalesID,Value為對應的資料。

OrderBy & OrderByDescending

OrderBy為SQL語法裡的ORDER BY操作,根據所指定的欄位進行排序,預設為升冪排序;OrderByDescending和OrderBy一樣,但是以降冪排序。


Scenario:

將Good Table依據Price的大小排序(預設小到大)

Result:


SQL:

Any

Any是LINQ to Entities較特別的用法,回傳型態為Boolean值,只要集合裡任何筆資料欄位值符合條件就回傳True,否則回傳False。

Scenario:

判斷是否Good Table裡的資料SalesID欄位是否有為2的值

Result:


SQL:


Join

Join為SQL語法中的INNER JOIN的操作,可將兩個Table,依照指定的相關欄位,合併成一個Table。


Scenario:

將User與Good兩個Table依照User.ID與Good.SalesID結合起來,
var data = [A Table].Join([B Table], [A Join Key], [B Join Key], ....)
Join()第一個Argument為要Join的B Table,第二個Argument為A Table要Join的Key,第三個Argument為B Table要Join的Key,第四個代表最後的Join Table要有那些欄位,範例中是Table A, B所有欄位。

Result:


SQL:


以上只是簡單介紹幾個與查詢相關的LINQ to Entities,看完是不是覺得LINQ to Entities真是個好用的東西,對於像限量這樣懶的人根本就是個神器,LINQ to Entities其實還有許多好用的Extension,這就待下次的介紹了。



相關連結:
LINQ to Entity Part II


參考資料:


留言