LINQ - 黃忠成資訊工作室
Download
Report
Transcript LINQ - 黃忠成資訊工作室
LINQ 全面透析
黃忠成資訊工作室
LINQ To CLR
LINQ To SQL
LINQ To Entities
• LINQ To Objects
• LINQ To XML
• LINQ To DataSet
• SQL Server Support
• O/R Mapping
• SQL Injection Prevent
• Multi-Database Support
• O/R Mapping
• EDM
• SQL Injection Prevent
VB.NET 2008新語法
• Partial Class
• Partial Method
• Anonymous Function Expression
• Object Initialize
什麼是LINQ
• LINQ全名為
– Language Integrated Query
• Language指的是程式語言
• Integrated指的是整合
• Query指的是查詢
– 因此,LINQ就是[整合至程式語言中的查詢敘述語法]
• 那些程式語言支援LINQ
–
–
–
–
C# 2008
VB.NET 2008
Ruby
Phyton
為什麼我們需要LINQ
• 你是否需要在陣列中尋找一元素?
• 你是否需要在陣列中尋找多個符合條件的元素
• 在LINQ前,你是怎麼做?
– 迴圈與列舉一一比對是唯一方法
– 更好的方法,使用Delegate.
• 在LINQ後,你能怎麼做?
– 使用SQL LIKE語法,像查詢SQL資料庫般查詢陣列
– 像查詢SQL資料庫般,LINQ允許你對多個陣列進行JOIN並查詢
LINQ To Objects
一個簡單的例子
傳統寫法
使用LINQ
LINQ的設計初衷
提供一組常用的運算模組,例如搜尋,聯集(Join)搜尋,協助
設計師完成日常的運算工作
透過程式語言與編譯器的協助,提供新的程式語法,將使用
這個運算模組的動作,變成程式語言的一部份.
LINQ的架構
LINQ語法規則基礎
Alias
Where 語句
查詢條件
FROM語句
DataSource
LINQ的資料來源(Data Source)
• 必須是實作IEnumerable(Of T)的物件
• 陣列
– Dim List As String() = {“code6421”, “tom”, “mary”}
• List(Of T)
– Dim Data = New List(Of String)()
• 與.NET Framework結合應用
– Dim List = From S1 In Directory.GetFiles("C:\Windows") Where
S1.Contains("w")
常用術語解釋
• Data Source,資料來源,元素集
– 一個實作IEnumerable(Of T)的物件
• 查詢回傳集
– 由查詢式回傳的物件
• 元素
– 回傳集,元素集中的某一元素
• 查詢式
– LINQ 語句
了解Where語句
• Where語句後?
– 在LINQ To Objects中,Where語句後是一段程式碼
• Directory.GetFiles("C:\Windows") Where
S1.Contains("w")
S1.Contains(“w”)是一段回傳Boolean值的程式碼
– 同理,下面的寫法也是允許的
• AND
– From s1 In List Where s1 Mod 5 = 0 And s1 > 20
• OR
– From s1 In List Where s1 Mod 5 = 0 Or s1 > 20
Contains函式的秘密
• From s1 In Data Where s1.Name.Contains(likeName)
– s1 = String
– String擁有Contains函式
– 所以,可以用s1.Contains來判別該元素是否擁有特定字元
– 同理
– From s1 In Data Where s1.Name.StartsWith(likeName)
– 可以判定該元素是否以特定字元開始
– Contains的簡化式
• Dim result = From s1 In Data Where s1.Name Like "*V*"
• Dim List As Integer() = {15, 20, 25, 30, 34}
Dim Result = From s1 In List Where s1 Mod 5 = 0
了解Where語句2
• 定義函式
– From s1 In List Where Filter(s1)
• 類別函式
• 類別靜態函式
In查詢式
Where語句於執行時期
• Where語句後的程式碼,會被編成一函式
• 當我們列舉查詢式回傳集中元素時(以For Each,For),每個
元素都會被傳入此函式比對,以傳回值判定是否取回該元
素或是跳過進行下一個元素之比對.
• LINQ To Objects的重要觀念,有Where條件時
– 在開始列舉時,每一個元素都會被送往某一函式比對
– 模式與你用迴圈列舉相同.
排序
• 正向排序
• 倒序
• 多重排序
Inner Query
• Query 中可包含另一Query
• Query As Data Source
了解Select語句
• Default Select
– From s1 In Data
• Explicit Select
– From s1 In Data Select s1
• Select New
– From s1 In Data Select Name = s1.Name + "," + s1.Age.ToString()
JOIN
JOIN的模式
• 預設為INNER JOIN,在JOIN時,左邊找到的,右邊也要找到,
否則就不列出
• GROUP JOIN
• 以GROUP JOIN模擬LEFT JOIN
• 以GROUP JOIN模擬FULL OUTER JOIN
Grouping
• Simple Group
•
[Group <Data Source> By <key variable> = <key from Data Source> Into <Alias Variable> = Grou
p Select <Anonymous Type>
另一個Group例子
• Group Alias Variable
• Multi-Key Grouping
常用語句
• Take
• Skip
• Any
• All
Take
• Take
– 由查詢回傳集中取出特定元素
From s1 In persons Take 2
• TakeWhile
– 由查詢回傳集中以特定條件比對,取出元素
From s1 In persons Take While s1.Age = 18 Or s1.Age = 28
注意! Take While是比對指定條件,當有元素不符合時,Take
While就會結束,換句話說,當第一個元素之age不等於18或28
時,Take While就會結束,即使第二三個元素符合條件.
Skip
• Skip
– 跳過查詢回傳集中特定數量元素後開始取得元素
From s1 In persons Skip 1
• Skip While
– 跳過查詢回傳集中符合特定條件之元素後開始取得元素
From s1 In persons Skip While s1.Age = 18
注意! Skip While是比對指定條件,當有元素不符合時,Ski Wh
ile就會結束,換句話說,當第一個元素之age不等於18時,Skip
While就會結束,列出所有元素,即使第二三個元素符合條件.
Distinct
• Distinct
– 惕除查詢回傳集重複元素
Dim nums() = {1, 1, 3, 4, 5}
Dim Result = From s1 In nums Distinct
For Each item In Result
Console.WriteLine(item)
Next
Aggregate 語句
• Aggregate 語法規則
Aggregate <alias> In <datasource> <Where> <Where Expression) Into <expression>
• Any的例子(判斷元素集中是否包含符合條件的元素)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 18, "002"))
persons.Add(New Person("mary", 18, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Any(s1.Age = 18)
Console.WriteLine(Result)
• Any後的語句與Where後語句相同,是一段程式碼
Aggregate語句結合Where
• Aggregate也可以與Where整合
• Aggregate也可以與Join整合
Aggregate敘述重要觀念
Aggregate通常傳回單值,例如Boolean,數值
Aggregate後的語法與From…語句幾乎相同
Aggregate可包含Where , Join , Group 等語句,與From..
相同
All
• All的例子(判斷元素集中是否全數符合條件)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 18, "002"))
persons.Add(New Person("mary", 18, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Any(s1.Age = 18)
Console.WriteLine(Result)
• All後的語句與Where後語句相同,是一段程式碼
Average,Count
• Average的例子(取平均值)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Average(s1.Age)
Console.WriteLine(Result)
• Count(取元素數)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Count(s1.Age >= 19)
Console.WriteLine(Result)
Min,Max
• Min(取最小值)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Max(s1.Age)
Console.WriteLine(Result)
• Min(取最大值)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Min(s1.Age)
Console.WriteLine(Result)
Sum
• Sum(加總)
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = Aggregate s1 In persons Into p1 = Sum(s1.Age)
Console.WriteLine(Result)
• Using Sum With Build-Type
•
Dim nums() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim Result = Aggregate s1 In nums Into p1 = Sum(s1)
Console.WriteLine(Result)
以Group結合Sum運算
• Aggregate是傳回單值
• 如需傳回元素集,可使用Group語句進行
• 寫法與Aggregate後面敘述幾乎相同
First
• First
– 取得第一個元素
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = (From s1 In persons Where s1.Age >= 18).First()
Console.WriteLine(Result.Age)
• 如果沒有元素符合,First將會拋出例外
FirstOrDefault
• FirstOrDefault
– 當沒有元素時,回傳Nothing,但不引發例外
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = (From s1 In persons Where s1.Age >= 50).FirstOrDefault()
If Not Result Is Nothing Then
Console.WriteLine(Result.Age)
End If
Last,LastOrDefault
• Last
– 取得查詢集的最後一個元素
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = (From s1 In persons Where s1.Age >= 18).Last()
Console.WriteLine(Result.Age)
• LastOrDefault
– 同Last,但如果查詢集為空,那將回傳Nothing
Dim persons = New List(Of Person)
persons.Add(New Person("code6421", 18, "001"))
persons.Add(New Person("tom", 28, "002"))
persons.Add(New Person("mary", 19, "002"))
Dim Result = (From s1 In persons Where s1.Age >= 50).LastOrDefault()
If Not Result Is Nothing Then
Console.WriteLine(Result.Age)
End If
查詢語句的回傳值
• 查詢語句的回傳值,多數是IEnumerable(Of T)型別
• IEnumerable(Of T)定義了First函式
• 一個關鍵例子
Dim nums() = {1, 2, 3, 4, 5}
Dim Result = nums.First()
• Array並不是IEnumerable(Of T),為何有First函式?
Extension Method
• 什麼是Extension Method
• Extension Method必須定義在Module中
• 一個簡單的例子
• LINQ Framework就是一群Extension Method的結合
LINQ與編譯器
• 使用Reflector 看我們的程式.
• Extension Method是LINQ Framework的底層架構
From LINQ Expression To Direct Call
Extension Method
• Function Expression 與 LINQ Extension Method
• Distinct
• Sum
• Average
• Min
• Max
• SkipWhile,TakeWhile
Where And Why
LINQ Expression .VS. Direct Call
• LINQ Expression的好處
– 直覺,與SQL語法類似
– 易讀
• LINQ Expression的缺點
– 敘述過長
– 受限於語法規則,無法達到Direct Call的相同效果
• 何時使用Direct Call
– 對一元素集進行單一運算,例如Sum,Average等等
– 當需要進階查詢時,例如Distinct,TakeWhile,SkipWhile等等
漸進式查詢
• 查詢式何時執行?
– 當程式嘗試取出元素時
• For Each等列舉式,First等函式
• 實作漸進式查詢
– 要點1 使用IEnumerable(Of T)為參數型別
– 要點2 所有Query回傳值皆為IEnumerable(Of T)
– 要點3 傳遞前不要進行列舉動作,否則查詢式會先執行,接下來的動
作為疊加式查詢,對效能會有影響
LINQ To XML
LINQ To XML的特色
• 更直覺的XML建立語法
• 與LINQ查詢語句結合的XML查詢式
• 更方便的XML文件操作
建立XML文件
• VB.NET 2008的新XML建立語法
Dim xmlDoc = _
<Customers>
<Customer Name="code6421" Age="18"/>
<Customer Name="tom" Age="28"/>
<Customer Name="david" Age="38"/>
</Customers>
xmlDoc.Save("C:\Test.xml")
Test.xml
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="code6421" Age="18" />
<Customer Name="tom" Age="28" />
<Customer Name="david" Age="38" />
</Customers>
新增XML Node
• 新增Node至尾端
Dim xmlDoc = XDocument.Load("C:\Test.xml")
xmlDoc.<Customers>(0).Add(<Customer Name="Hung" Age="16"/>)
xmlDoc.Save("C:\Test2.xml")
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="code6421" Age="18" />
<Customer Name="tom" Age="28" />
<Customer Name="david" Age="38" />
<Customer Name="Hung" Age="16" />
</Customers>
新增XML Node
• 新增Node至最前
Dim xmlDoc = XDocument.Load("C:\Test.xml")
xmlDoc.<Customers>(0).AddFirst(<Customer Name="Hung" Age="16"/>)
xmlDoc.Save("C:\Test2.xml")
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="Hung" Age="16" />
<Customer Name="code6421" Age="18" />
<Customer Name="tom" Age="28" />
<Customer Name="david" Age="38" />
</Customers>
新增Attribute至既定Node
• Add Attribute
Dim xmlDoc = XDocument.Load("C:\Test.xml")
xmlDoc.<Customers>(0).<Customer>(0).Add(New XAttribute("Tag", "Test"))
xmlDoc.Save("C:\Test2.xml")
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="code6421" Age="18" Tag="Test" />
<Customer Name="tom" Age="28" />
<Customer Name="david" Age="38" />
</Customers>
新增為子Node
• 新增為子Node
Dim xmlDoc = XDocument.Load("C:\Test.xml")
Dim child = <Order ID="001"/>
xmlDoc.<Customers>(0).<Customer>(0).Add(child)
xmlDoc.Save("C:\Test2.xml")
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="code6421" Age="18">
<Order ID="001" />
</Customer>
<Customer Name="tom" Age="28" />
<Customer Name="david" Age="38" />
</Customers>
<%=...%>語句
• 透過<%=...%>將變數與XML文件結合
Dim xmlDoc = _
<Customers>
</Customers>
For Each item In data
xmlDoc.Add(<Customer Name=<%= item %>></Customer>)
Next
xmlDoc.Save("C:\Test3.xml")
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer Name="code6421"></Customer>
<Customer Name="tom"></Customer>
</Customers>
LINQ To XML的架構圖
常用類別
類別
說明
XDocument
XML文件的容器,用於讀取或建立XML文件
XElement
XML Element
XAttribute
XML Attribute
XComment
XML 文件註解
XNamespace
XML 命名空間
XCData
XML 中的CData節點
常用類別示意圖
XDocument
XNamespace
XCData
XElement
XAttribute
運用LINQ XML Framework類別來建立XML文件
LINQ To XML查詢式
• 一個簡單的例子
<Customers>
<Customer Name="code6421" Age="18"/>
<Customer Name="tom" Age="28"/>
<Customer Name="david" Age="38"/>
</Customers>
使用Order By
• Order By
Take,Skip
• Take
• Skip
Grouping
• Using Grouping
Join
• Use Join
Group Join and Sum
• Group Join And Sum
Group Join And Average
• Group Join And Average
Min,Max,Count
• Min函式
• Max函式
• Count函式
LINQ To XML 與Aggregate語句
• 與LINQ To Objects相同,LINQ To XML也可以用Aggregat
e
LINQ To XML與LINQ To Objects
• 同樣的查詢語句
• Data Source與元素描述略為不同
<…>
• <…>
– 取得特定的子Element
– 此法無法取得子Element的Element
正確
錯誤,Test不是Orders
(Root)的子Element
正確寫法: From cust In xmlDoc.<Order>.<Test>
…<…>
• …<…>取得所有符合的Element
– 與<…>不同,此法將可取得所有符合條件的Element
查詢實例1 - RSS
• Load RSS
• Find in RSS
LINQ To Dataset
LINQ To DataSet的設計初衷
• 將LINQ語法套用到DataSet與DataTable
• 為DataTable提供更強大的查詢功能
一個簡單的例子
• 準備Table
開始查詢
• Field(Of T)的意義
– 當值非DBNull,回傳值
– 當值無法轉為指定型別,產生例外
– 當值為DBNull,回傳Nothing
具條件的查詢
• 使用Where
存取Row Version
• 使用RowVersion來查詢與取得資料
Group
• 運用Group
運用Join
• 運用Join
Skip,Take
• Using Skip
• Using Take
Sum,Min,Max,Average
• Using Group Join With Sum
• Using Min
• Using Max
• Using Average
LINQ To DataSet與LINQ
• 不同的Data Source,元素描述
• 相同的語法規則