LINQ to SQL系列Part 9-Using a Custom LINQ Expression with the control

LINQ to SQL系列Part 9-Using a Custom LINQ Expression with the <asp:LinqDatasource> control

本文英文原版:
http://weblogs.asp.net/scottgu/archive/2007/09/07/linq-to-sql-part-9-using-a-custom-linq-expression-with-the-lt-asp-linqdatasource-gt-control.aspx

在本系列的Part 5部分,我提到了.NET 3.5裏新引入的<asp:LinqDataSource>控件,利用它我們可以輕易的將ASP.NET UI控件綁定到LINQ to SQL數據模型.在另一篇有關<asp:ListView>控件的文章裏(Part 1 - Building a Product Listing Page with Clean CSS UI),我多多少少演示了其用法.

在這些文章裏,我執行的查詢都是比較直觀的(其where子語句都是處理單個表的數據),今天的文章,我將演示如何基於LinqDataSource控件來使用的比較全的LINQ查詢表達式,以及任意的LINQ to SQL查詢表達式.

Quick Recap: <asp:LinqDataSource> with a Declarative Where Statement

在本系列的Part 1 和 Part 5部分,我演示瞭如何利用LinqDataSource控件內置的條件過濾功能,來對某個LINQ to SQL數據模型進行限制.

比如,假定我們已經爲Northwind數據庫創建了一個LINQ to SQL數據模式(具體過程可參考Part 2部分),我們可以在頁面上添加一個<asp:LinqDataSource>控件,並設置一個<where>過濾條件,僅僅返回某個指定category的所有產品(通過指定"categoryid"的值):

圖1

然後我們可以將一個<asp:gridview>控件指向該數據源,並啓用分頁、編輯、排序功能,如下:

圖2

當我們運行上述頁面的時候,這個基於Product數據模式的GridView將自動的支持排序、分頁、編輯功能.

圖3

像上面一樣顯式地使用<where>參數,在大多數情況下沒有問題。但是如果我們想使過濾條件更爲複雜一些呢?比如,我們想動態的設置countries,而只將這些國家的產品顯示出來,這麼辦呢?


利用<asp:LinqDataSource>控件的Selecting事件

爲了處理用戶定製查詢,你可以構建一個事件處理器來處理<asp:LinqDataSource>控件的"Selecting"事件.在該事件處理器裏你可以任意地寫代碼,以檢索你想要得到的結果.爲此,你可以利用一個LINQ to SQL查詢表達式, 或調用一個存儲過程,或使用一個Custom SQL Expression(用戶定製查詢),以對該LINQ to SQL數據模型進行檢索.一旦你檢索到了一連串的數據(a sequence of data),你需要做的就是將其賦值給一個LinqDataSourceSelectEventArgs對象的"Result"屬性.然後,<asp:LinqDataSource>控件將對這一連串的數據進行處理.比如,如下是一個LINQ to SQL查詢表達式,它將指定國家的產品檢索出來:

VB:

圖4

C#:

圖5
注意:你沒有必要在事件處理器裏寫具體的查詢語句,相反你可以將具體的查詢語句封裝在一個helper method方法裏,然後在事件處理器裏直接調用即可.在Part 8的前面部分我演示瞭如何來創建這種helper method(比如GetProductsByCategory helper method)

現在運行頁面,你將只會看到指定國家的產品:

                    圖6

以上很酷的一點需要引起我們的注意,那就是分頁和排序依然基於GridView——即使我們使用一個用戶自定義的Selecting事件來檢索數據.而分頁和排序其實發生在數據庫端——這就意味着我們只需要根據GridView裏當前頁面的page index索引,僅僅從數據庫檢索出10條產品信息即可(這樣就大大的提高了效率)

你可能要問,就算我們使用了自定義selecting事件,我們又這麼可能得到高效的分頁和排序功能支持呢?答案在於LINQ使用延緩執行模式(deferred execution model)——就是說,在你對結果反覆進行操作完成之前,查詢沒有真正的執行過.這種延緩執行模式的好處之一在於:你可以構建精細的查詢(nicely compose queries),更多信息請參閱Part 3部分.

在上面的"Selecting"事件處理器裏,我們聲明瞭一個自定義的LINQ查詢,然後對"e.Result"屬性進行賦值.不過我們還沒有真正的執行它(因爲我們還沒有遍歷結果或調用ToArray() 或 ToList()方法). LINQDataSource對查詢自動地運用Skip()和Take(),同時運用一個"orderby" expression——根據GridView控件的page index和sort preference(即跟據什麼來排序),來對這些值自動的進行運算.然後LINQDataSource執行LINQ查詢並返回數據. LINQ to SQL將確保分頁和排序邏輯是發生在database端,僅僅要用到的那10條產品記錄被返回.

注意下面,我們又是怎樣使用GridView來編輯和刪除產品的:

圖7

只要我們的Selecting事件指派了這樣的一個Result query——其結果集(result sequence)是規則的實體對象(比如Product, Supplier, Category, Order等),那麼編輯/刪除功能就得到很好的支持,LINQDataSource會自動的進行處理.

關於使用LINQ to SQL進行updates操作的更多內容,請參閱Part 4部分,關於使用LinqDataSource來進行Updates實際操作的示例,請看Part 5部分.


在Selecting事件裏執行Custom Query Projections

LINQ強大之一在於它可以定製"shape" 或 "project"數據.你可以在一個LINQ to SQL表達式裏指出你僅僅想從結果裏返回一個子集.關於這方面的更多內容請參閱Part 3部分.

比如,我們想修改"Selecting"事件處理器,使GridView顯示產品的指定信息.我們想將顯示ProductID, Product Name, Product UnitPrice, the Number of Orders(產品的訂購量),以及總的Revenue之和.對後兩項我們可以使用如下的LINQ expression,如下:

VB:

圖8

C#:

圖9

注意:上述Revenue聲明裏用到的Sum方法是Extension Method的一個範例,而它使用的函數又是Lambda expression的一個範例.而結果類型是一個anonymous type(匿名類型)——因爲它的類型是由查詢表達式推斷出來的.Extension Methods, Lambda Expressions, 以及Anonymous Types都是VS 2008裏VB 和 C#的新語言特性.

當把結果綁定到GridView後,UI看起來和下面的差不多:


圖10

注意,在GridView裏分頁和排序依然工作正常——即使我們使用的是自定義的LINQ shape/projection數據. 

與自定義shape/projection不太協調的是,它不支持inline editing.因爲我們在Selecting事件裏使用了一個custom projection,因此LinqDataSource沒有辦法確切的知道如何更新實體對象.如果我們要對使用shaped類型數據的GridView添加編輯功能,要麼轉而使用ObjectDataSource控件(我們可以在裏面提供定製的Update方法來來處理updates),要麼把用戶導航到另一個頁面執行更新——比如將一個DetailsView 或 FormView控件綁定到一個Product實體以進行更新.

總結:

利用LinqDataSource內置的顯式過濾功能,我們可以很容易地對一個LINQ to SQL數據模型執行常見的查詢操作.

要實現更高級點的或用戶自定義過濾條件,我們可以利用LINQDataSource的Selecting事件.我們可以在該事件裏執行對LINQ to SQL數據的過濾和檢索的任何邏輯.你可以調用方法來檢索數據,使用LINQ Query Expressions,調用存儲過程或調用一個Custom SQL Expression來實現.

希望這些對你有所幫助!

Scott

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章