2012年3月26日 星期一

Dynamic LINQ + Entity Framework - Part.1:MS SQL Server, LINQPad


是的,動態LINQ查詢,這並不是一個新的LINQ查詢方式,早在 2008年1月7日時 Scott Guthrie 就已經介紹過了,

ScottGu’s Blog - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

當時候是因應 VS2008 以及 .NET Framework 3.5 的 Release 而出現,那時候大家還正在摸索如何應用 LINQ,

雖然說現在大部分的專案中都會採用 LINQ to SQL or ADO.NET EF Framework,

使用並且操作強型別的資料集合對於設計階段有很大的幫助,

但是使用者的需求是千變萬化,永遠不可能照著系統規格走,甚至永遠都會有萬惡的「需求修改」出現,

這時候不論你用的技術如何強大或是功力多麼高深,永遠是無法戰勝客戶的需求以及老闆的壓力……

離題了…

對於動態查詢的功能,程式設計師使用組 SQL Command 查詢字串的方式是可以讓客戶的無限想像變換為可能,

但是到了使用LINQ查詢,好像一切都變得好複雜……

 

因為強型別的關係,程式設計師無法隨心所欲的去任意使用「字串」來讓不可能變成可能,

常常在程式中為了要達到所謂的查詢條件動態,就會看到程式中會有一堆的 if…else 或是 switch 判斷,

為了要讓 LINQ 查詢式可以隨著條件的變動而有所更改,很多程式設計師可以說用盡了很多的方法。

 

後來 Joe Albahari, Ben Albahari 提供了「PredicateBuilder」,算是有效解決了很多動態查詢的限制與困難,

不過 PredicaterBuilder 會比較適合固定查詢欄位或是只在幾個欄位去做查詢條件的動態組合,

一旦遇到真的要向組字串的方式那樣動態,PredicaterBuilder 似乎也不太能夠滿足客戶的需求。

 

Dynamic LINQ

Scott’s Blog - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

Rai Kaimal - Dynamic String based Queries in LINQ - Dynamic Expression API

Will 保哥 - Dynamic LINQ 讓 LINQ 的世界變的更美好

以上三個參考連結都有詳細的說明 Dynamic LINQ 的使用方式。

 

如果要取得 VS 2008 C# Sample Code 的 Dynamic LINQ 程式碼,可以到以下的連結取得:

Official Visual Studio 2008 C# Samples

DynamicQuery

 

假如你想要下載 VS 2010 以及 .NET Framework 4.0 的版本,就要另外到以下的連結中取得:

Visual Studio 2010 的 C# 4.0 範例

雖然網頁中依然有「DynamicQuery」的說明,但是在下載的範例程式碼裡就是找不到 DynamicQuery,

image

不過在「KKBruce」部落格中找到了 DynamicQuery 程式碼的線索,KKBruce - LINQ Dynamic Query

原來在我們安裝 VS2010 的同時,也會把這些 Sample Code 一併複製到我們的電腦中,

Sample Code 的目錄位置是:

「C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1028」

image

壓縮檔「CSharpSamples.zip」裡面路徑「LinqSamples > DynamicQuery」

image

在「DynamicQuery」目錄中可以看到一個方案檔,另外有個「Dynamic Expressions.html」這是使用說明文件,

我建議各位務必要詳讀一遍,在讀過之後大致就會了解使用的方式,

image

 

在「LinqSamples > DynamicQuery > DynamicQuery」目錄下的「Dynamic.cs」檔案,

SNAGHTMLf44c40

這個檔案就是這個Dynamic LINQ的重點,全部的檔案行數總共有將近 2300 行,

我曾經試著想要了解它,不過最後還是放棄了…

SNAGHTMLf400a0

 

 

使用 Dynamic LINQ

如果想要在專案中去使用這個「Dynamic.cs」檔案內容的話,我不建議直接把檔案複製然後貼到你的專案中。

SNAGHTMLf2d7fb

比較建議的方式,就是建立一個「類別庫專案」,而這個專案就只是放置這個「Dynamic.cs」而已,

這麼做是有好處的,只要在專案中去引用就可以,在你建立的各個專案中去重複使用這個類別庫,

而且還可以在「LINQPad」中加入參考,就可以在 LINQPad 中使用Dynamic LINQ了。

 

以下是我將「Dynamic.cs」放至於類別庫的作法

image

一、建立名稱為「DynamicLinq」的類別庫專案。

二、要記得專案要加入「System.Data.Linq」參考,不然引用這個專案時會無法使用到 Dynamic LINQ 的方法。

三、為了與類別名稱一致,所以我將檔名改為「DynamicQueryable.cs」也可以不用改。

四、將原本使用「System.Linq.Dynamic」namespace改為這個類別庫的namespace。

 

 

於 LINQPad 中使用 Dynamic LINQ

在 LINQPad 中加入一個已經在 VS2010 建立的專案,這個專案有加入使用 EF

SNAGHTML11c8e4f

 

在 LINQPad 中加入剛才建立的「DynamicLinq」專案參考,按下「F4」就會出現「Query Properties」視窗

SNAGHTML11fa27b

 

按下「Browse」把剛才建立「DynamicLinq」專案的dll檔案,加入這個「DynamicLinq.dll」

如果你像要在往後啟動 LINQPad 都要使用這個專案參考的話,可以按下「Set as default for new queries」

新的Query Tab都會預設加入並使用這個專案參考。

SNAGHTML11fa27b[7]

 

加入了專案的dll檔案還不夠,必須要加入 namespace import 才可以使用,

SNAGHTML1246fb8

在中間的文字輸入框輸入「 DynamicLinq」就可以,如果還要加入其他的 namespace,就在下一行輸入即可,

如果希望以後新的 Query Tab 一開始就預設加入使用 namespace 可以按下「Set as default for new queries」

SNAGHTML127c6bd

上述的動作完成之後,就按下「OK」按鍵以關閉設定視窗。

 

開啟一個新的 Query Tab 並且將 Language 選為「C# Statement(s)」,然後輸入一些 LINQ 查詢式,

下圖中的查詢式就使用了 DynamicQueryable Extensions 的內容,

SNAGHTML131878c

執行結果:

image

接著看看這段 LINQ 查詢式所產生的 SQL Command:

SELECT TOP (10) 
[Project1].[CustomerID] AS [CustomerID], 
[Project1].[CompanyName] AS [CompanyName], 
[Project1].[ContactName] AS [ContactName], 
[Project1].[ContactTitle] AS [ContactTitle], 
[Project1].[Address] AS [Address], 
[Project1].[City] AS [City], 
[Project1].[Region] AS [Region], 
[Project1].[PostalCode] AS [PostalCode], 
[Project1].[Country] AS [Country], 
[Project1].[Phone] AS [Phone], 
[Project1].[Fax] AS [Fax]
FROM ( SELECT 
    [Extent1].[CustomerID] AS [CustomerID], 
    [Extent1].[CompanyName] AS [CompanyName], 
    [Extent1].[ContactName] AS [ContactName], 
    [Extent1].[ContactTitle] AS [ContactTitle], 
    [Extent1].[Address] AS [Address], 
    [Extent1].[City] AS [City], 
    [Extent1].[Region] AS [Region], 
    [Extent1].[PostalCode] AS [PostalCode], 
    [Extent1].[Country] AS [Country], 
    [Extent1].[Phone] AS [Phone], 
    [Extent1].[Fax] AS [Fax], 
    (SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[Orders] AS [Extent2]
        WHERE [Extent1].[CustomerID] = [Extent2].[CustomerID]) AS [C1]
    FROM [dbo].[Customers] AS [Extent1]
)  AS [Project1]
WHERE (N'London' = [Project1].[City]) AND ([Project1].[C1] >= 10)
ORDER BY [Project1].[CustomerID] DESC

 

 

再來看看另外一種查詢,操作 Contains 的查詢,這個查詢在 SQL 中將會執行 LIKE,

image

執行結果:

image

轉換的 SQL Command:

SELECT 
[Extent1].[CategoryID] AS [CategoryID], 
[Extent1].[CategoryName] AS [CategoryName], 
[Extent1].[Description] AS [Description], 
[Extent1].[Picture] AS [Picture]
FROM [dbo].[Categories] AS [Extent1]
WHERE [Extent1].[CategoryName] LIKE N'%a%'
ORDER BY [Extent1].[CategoryID] ASC

 

 


以上簡單的介紹 Dynamic LINQ 的內容,另外也告訴各位如何在我們的電腦中找出這一個程式檔,

另外再建立一個類別庫專案,讓這個 Dynamic LINQ 可以在往後的專案中去重複使用,

最後說明如何在 LINQPad 中的查詢也能夠使用 Dynamic LINQ 功能,

這一篇先簡單的做個介紹與使用說明,下一篇將會在一個 ASP.NET MVC 3 的專案中使用 Dynamic LINQ。

 

參考連結:

Scott’s Blog - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

Rai Kaimal - Dynamic String based Queries in LINQ - Dynamic Expression API

Will 保哥 - Dynamic LINQ 讓 LINQ 的世界變的更美好

Official Visual Studio 2008 C# Samples

Visual Studio 2008 C# Samples - DynamicQuery

Visual Studio 2010 的 C# 4.0 範例

KKBruce - LINQ Dynamic Query

 

以上…

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。