天天看點

一起談.NET技術,ASP.NET 4過濾資料新控件QueryExtender

  在ASP.NET 4中的一個新的控件是QueryExtender。QueryExtender控件是為了簡化LinqDatasource或EntityDataSource控件傳回的資料過濾而設計的,它主要是将過濾資料的邏輯從資料控件中分離出來。使用QueryExtender是十分容易的事,隻需要簡單往頁面上增加一個QueryExtender控件,指定其資料源是哪個控件并設定過濾條件就可以了。比如,當在頁面中顯示産品的資訊時,你可以使用該控件去顯示那些在某個價格範圍的産品,也可以搜尋使用者指定名稱的産品。

  當然,不使用QueryExtender控件的話,LinqDataSource和EntityDataSource也是可以過濾資料的。這兩個控件都有一個where的屬性,可以指定過濾資料的條件。QueryExtender提供的是一種更簡單的方式去過濾資料。本文包含了一系列的例子(可以,在本文最後下載下傳),展示了QueryExtender的強大威力。

  首先要注意的是,QueryExtender控件隻能配合LinqDataSource和EntityDatasource使用。它不能去過濾SqlDataSource控件的資料集。當然,使用該控件的話,你必須使用LINQ或者ADO.NET Entity架構。對這兩者的讨論已經超出本文讨論的範圍。簡而言之,LINQ和Entity Framework是微軟的對象關系映射工具,使用的是LinqDataSource和EntityDataSource兩個控件,它們允許開發通過ORM的解決方案去通路資料庫。

  本文附錄的代碼下載下傳中,提供的例子使用的是ADO.NET Entity架構,并對Northwind資料庫中的Products,Categories和Suppliers三張表進行了實體模組化。其中資料庫檔案Northwind.mdf位于網站的App_Data目錄下,App_Code目錄下則有ADO.NET Entity架構的模組化檔案Northwind.edmx,它定義了對象實體和資料庫表之間的關系。

  正如在本文介紹部分所說的,QueryExtender控件是配合LinqDatasource 和EntityDataSource 控件使用的。考察一個頁面,允許使用者輸入一個最小的價格,之後就能顯示小于或等于這個價格的所有産品。這個很容易用如下代碼實作: 

<b>Show All Prices Less Than:</b>

$<asp:TextBox ID="txtMaxPrice" runat="server"></asp:TextBox>

<asp:Button ID="btnDisplayProducts" runat="server" Text="Show Products" />

<asp:GridView ID="gvProducts" runat="server" DataSourceID="dsProducts" ...>

...

</asp:GridView> <asp:EntityDataSource ID="dsProducts" runat="server"

ConnectionString="name=NorthwindEntities"

DefaultContainerName="NorthwindEntities" EnableFlattening="False"

EntitySetName="Products" Where="it.UnitPrice <= @UnitPrice">

<WhereParameters>

<asp:ControlParameter ControlID="txtMaxPrice" Name="UnitPrice"

PropertyName="Text" Type="Decimal" />

</WhereParameters>

</asp:EntityDataSource>

一起談.NET技術,ASP.NET 4過濾資料新控件QueryExtender

   在上面的例子中,當使用者在txtMaxPrice文本框中輸入價格并點“Show Products”按鈕後,會産生一個postback。在postback事件中,gridview與dsProducts這個資料源控件綁定,并查詢Products表的内容,應用where條件去篩選出那些價格低于或等于在txtMaxPrice文本框輸入的價格的産品。這個篩選可以象上文那樣設定,也可以在程式中設定,隻需要修改EntityDataSource 控件的selecting事件即可。

  使用EntityDataSource或者LinqDataSource兩個控件的篩選邏輯去完成篩選有兩個缺點。首先,它們都僅提供了有限的篩選功能,當然,有時對單一條件的篩選是可以應付的,但如果面對的是多條件篩選,比如要顯示價格低于某個數值并且産品名,供應商或者目錄包含某個指定的字元串,象這樣的複雜條件的話是難實作的。另外一個缺點是過濾的邏輯與資料擷取的邏輯功能都混雜在同一個控件中,維護其來比較麻煩。

  ASP.NET 4中的新控件QueryExtender,能讓我們可以設定更多更複雜的篩選條件。更為重要的是,使用該控件能将資料的擷取和資料的篩選兩部分邏輯清晰的分離―使用EntityDataSource或者LinqDataSource去獲得資料,QueryExtender則專門負責過濾資料,甚至可以設定如何去對結果集進行排序。

  使用QueryExtender 控件

  我們接下來看下該控件是如何做的,首先我們建立一個頁面是列出所有的産品,之後我們使用QueryExtender去列出産品中的一個部分。我們建立一個簡單的頁面,象剛才一樣,将gridview綁定到EntityDataSource控件中去,如下代碼所示: 

ConnectionString="name=NorthwindEntities" EntitySetName="Products"

DefaultContainerName="NorthwindEntities" EnableFlattening="False">

  接着,往頁面中增加一個QueryExtender控件。QueryExtender控件在工具面闆的Data面闆中,與gridview,EntityDataSource控件都是在一起的。接着,指定QueryExtender的資料源ID屬性,表明要篩選的是哪個資料源控件的資料,這通過設定

  QueryExtender的TargetControlID去設定,我們這裡設定的是dsProducts,如下: 

<asp:QueryExtender ID="qeRange" runat="server" TargetControlID="dsProducts">

</asp:QueryExtender>

我們現在可以開始設定QueryExtender的篩選邏輯了。QueryExtender的篩選邏輯使用的是一個或多個表達式。ASP.NET提供了如下表達式,包括:

  • RangeExpression –獲得小于,等于或者大于指定值的資料集合

  • SearchExpression –根據給出的字元串去進行搜尋

  • ControlFilterExpression –根據指定的控件的值去搜尋篩選,比如根據TextBox或者DropDownList

  • CustomExpression 和 MethodExpression -這兩個表達式基本基本是一樣的,它允許開發者去編寫自己的篩選邏輯。

  • OrderByExpression –根據開發者的指定,去排序列和根據指定的方向去排序

  比如,去顯示單價小于10美元的産品,我們可以增加一個RangeExpression,如下: 

<asp:RangeExpression DataField="UnitPrice" MinType="Inclusive" MaxType="Exclusive">

<asp:Parameter DefaultValue="0" />

<asp:Parameter DefaultValue="10" />

</asp:RangeExpression>

  在上面的例子中,請注意其中的inclusive和exclusive屬性。因為我們想看到的是大于或者等于0美元,但小于10美元的,是以我們對最小值設定的是inclusive包含的屬性,對最大值設定的是exclusive不包含的屬性。

  注意,RangeExpression能夠包含所有能在SqlDataSource, LinqDataSource和EntityDataSource控件中使用的參數控件,包括:

  • Parameter 控件,用來篩選寫死的值

  • SessionParameter 控件,根據session的值去篩選

  • ControlParameter 控件,根據指定控件的值去篩選

  例如,要根據使用者在文本框輸入的值去篩選,我們隻需要替換RangeExpression中的第2個參數為ControlParameter,即可:

<asp:ControlParameter ControlID="TextBoxID" DefaultValue="0" />

  更詳細的可以參考本文附錄代碼中的FilterDemo.aspx檔案。

  實際上,如果你懂得SQL,就應該知道,QueryExtender控件實際上是在後端為你生成了象如下這樣的代碼,以上文講到的例子為例: 

SELECT ...

FROM Products

WHERE UnitPrice >= 0 AND UnitPrice < 10

  使用SearchExpression根據字元串去篩選

  QueryExtender控件和SearchExpression使到很容易資料庫中根據字元串去篩選資料。SearchExpression允許你指定在一列或多列中去篩選符合指定字元串的資料,可以指定篩選出以某個字元串開頭,結尾或者包含的資料集合。下圖顯示了使用者可以在搜尋框中輸入字元串,頁面會顯示出産品名稱,目錄或供應商的名稱中以該字元串開頭的所有資料。比如在搜尋框中輸入字元a,則傳回的結果中,象Acme Tea,Acme Water,Alice Mutton和Aniseed Syrup都顯示出來,而Charteuse verte也顯示出來,因為它的供應商Aux joyeux ecclésiastiques,也是以a開頭的。

一起談.NET技術,ASP.NET 4過濾資料新控件QueryExtender

  這個例子也是很簡單,除了使用gridview和EntityDataSource控件外,指定了SearchExpression去獲得産品名稱,目錄名和供應商名,指定了搜尋模式是StartsWith,即以字母開頭的方式,并指定了根據文本框輸入的内容去篩選。代碼如下: 

<asp:QueryExtender ID="qeSearch" runat="server" TargetControlID="dsProducts">

<asp:SearchExpression DataFields="ProductName, Category.CategoryName,

      Supplier.CompanyName" SearchType="StartsWith">

<asp:ControlParameter ControlID="txtFilterText" />

</asp:SearchExpression>

  具體的可以參考本文附送代碼中的Search.aspx檔案

  如果你想篩選出符合者三個條件的所有記錄,則可以指定三個SearchExpression即可如下所示: 

<asp:SearchExpression DataFields="ProductName" SearchType="StartsWith">

<asp:SearchExpression DataFields="Category.CategoryName" SearchType="StartsWith">

<asp:SearchExpression DataFields="Supplier.CompanyName" SearchType="StartsWith">

  這樣,指定了三個SearchExpression表達式,它們的邏輯關系是AND。  

  用代碼實作篩選

  QueryExtender控件通過使用RangeExpression和SearchExpression使得定義篩選邏輯變得很容易。同樣,可以使用CustomExpression或者MethodExpression控件去通過代碼的方式去實作篩選邏輯。實際上,當需要應用篩選邏輯時,CustomExpression會觸發一個事件,你可以在這個事件裡編寫相關的處理代碼。而MethodExpression則有點不同,你要編寫一個靜态的方法,并傳入一個類型為IQueryable的對象并且傳回的對象也是要相同的類型。傳入該方法的對象實際上是在篩選邏輯前的一個查詢執行個體,可以在其中編寫你需要實作的查詢條件,最後要傳回這個查詢執行個體。

  下面我們更詳細去了解下MethodExpression。假設你要根據登陸了的使用者的身份去篩選資料,比如管理者能看到所有産品資訊但非管理者隻能看到沒打折的産品。則我們如上所述在靜态方法中,傳入IQueryable執行個體作為參數,傳回的也對象類型也必須是IQueryable類型的,如下:

// C#

public static IQueryable FilterBasedOnUser(IQueryable query)

{

if (Roles.IsUserInRole("Administrators"))

// Return the querywithout filtering

return query;

else

// Return only non-discontinued products

return query.Where(p => p.Discontinued == false);

}

' VB

Public Shared Function FilterBasedOnUser(ByVal query As IQueryable(Of Product))

   As IQueryable(Of product)

If Roles.IsUserInRole("Administrators") Then

' Return the querywithout filtering

Return query

Else

' Return only non-discontinued products

Return query.Where(Function(p) p.Discontinued = False)

End If

End Function

而在前端的代碼中,則隻需要使用MethodExpression指出引用的方法即可,如下所示:

<asp:QueryExtender ID="qeByMethod" runat="server" TargetControlID="dsProducts">

<asp:MethodExpression MethodName="FilterBasedOnUser" />

  對傳回的結果進行排序

  除了篩選資料外,QueryExtender控件還可以對篩選出來的資料集指定排列的順序。這可以通過OrderByExpression去實作,隻需要設定哪些字段是需要排序的并指出其排序的方向即可。比如要對ProductName進行升序排序的話,隻需要如下實作即可:

<asp:OrderByExpression DataField="ProductName" Direction="Ascending" />

<asp:OrderByExpression DataField="ProductName" Direction="Ascending">

<asp:ThenBy DataField="UnitPrice" Direction="Descending" />

</asp:OrderByExpression>

</asp:QueryExtender> 

  總結

  ASP.NET 4中新提供的控件QueryExtender,簡化了對資料的篩選,甚至還可以指定篩選出來的資料的排序。其中RangeExpression允許開發者指定篩選資料的方式,而篩選的邏輯可以通過使用CustomExpression或MethodExpression去編寫代碼實作。