[VS2010] ASP.NET 4.0 在資料存取以及資料控制項上的增強

[VS2010] ASP.NET 4.0 在資料存取以及資料控制項上的增強

ASP.NET 4.0 可以算是自從 2.0 開始以來最大幅度的改版,不論是 Web Forms,MVC,AJAX 還是核心服務 (Core Service),都做了不小的改變,為了因應在這幾年來瞬息萬變的 Web 應用程式技術與開發功能,像是 jQuery 這種 Framework 也是近幾年發展出來的,CSS 和跨瀏覽器的需求也是在第二次瀏覽器大戰延燒之下所產生的,而 ASP.NET 2.0 的核心在這段激烈的攻防戰中早已露出疲態,也刺激了 ASP.NET 團隊對核心部份做出大多數的改變,在前篇文章所提到的 Menu 的 semantically markup 和 FormView 更乾淨的 HTML 輸出就是很好的例子,當然 ASP.NET 4.0 的改變不只有那些而已,基於 .NET Framework 3.5 的 LINQ 以及 ADO.NET Entity Framework 的發展,在 ASP.NET 中也導入了一些延伸性的支援,本文所要介紹的就是兩個 ASP.NET 4.0 在資料存取與控制這部份的強化。

 

1. QueryExtender 讓基於 LINQ 的查詢更具擴充性。

 

自從 LINQ 於 .NET Framework 3.5 發表出來以後,在 C# 社群引起來非常大的震憾,因為它將存取物件集合的方式以類似於 SQL 指令的方式處理,LINQ to SQL 以及 Entity Framework 的 LINQ to Entities 更將範圍延伸到資料庫存取上,各式各樣的 LINQ Query Provider 也如同雨後春筍般發展起來,像是 LINQ to Active Directory, LINQ to Oracle 或 LINQ to Wikipedia 等等,似乎只要是可以用集合物件表示的資料,都可以用 LINQ 來查詢,只是這項褔利在 LinqDataSource 和 EntityDataSource 中似乎有一點侷限,雖然這兩個 Data Source Control 都有 Where 的屬性可以用,但是彈性就是不怎麼好,因為那是一個寫死的字串。

 

<asp:DropDownList AutoPostBack="true" ID="DropDownList1" runat="server">
    <asp:ListItem Value="0"></asp:ListItem>
    <asp:ListItem Value="25"></asp:ListItem>
    <asp:ListItem Value="100"></asp:ListItem>
    <asp:ListItem Value="400"></asp:ListItem>
</asp:DropDownList>
<asp:LinqDataSource
    ContextTypeName="ExampleDataContext"
    TableName="Products"
   
Where="Price>@UserPrice"
    ID="LinqDataSource1"
    runat="server">
    <WhereParameters>
        <asp:ControlParameter
            Name="UserPrice"
            DefaultValue="0"
            ControlID="DropDownList1"
            Type="Int32" />
    </WhereParameters>
</asp:LinqDataSource>
<asp:GridView
    DataSourceID="LinqDataSource1"
    ID="GridView1"
    runat="server">
</asp:GridView>

 

大家也都知道,像這種資料查詢的參數最好是多一點動態以及更寬廣的條件設定,甚至是排序的條件等,但 LinqDataSource 以及 EntityDataSource 在這個功能上受到了不少的限制,因此 ASP.NET 4.0 為了這兩個控制項開發了一個可以再延伸查詢功能的元件,稱為 QueryExtender (查詢延伸器),QueryExtender 可以在現有的 Data Source 上面加上查詢的過濾以及排序陳述,以在查詢結果中處理條件的篩選功能。像是範圍篩選 (RangeExpression),屬性篩選 (PropertyExpression),排序篩選 (OrderByExpression),選取篩選 (SearchExpression) 以及自訂的篩選器 (CustomExpression) 等,它可以達到以宣告式 (Declarative) 的方式來設定額外的查詢條件,因此對於 LinqDataSource 以及 EntityDataSource 的使用者是個大利多。

 

下表是 QueryExtender 所支援的查詢過濾器:

過濾器

說明

ControlFilterExpression

使用自來源資料容器控制項中選取的資料鍵建立資料庫查詢,此過濾器只支援 Dynamic Data。

CustomExpression

為資料來源設定一個使用者定義的過濾器,可以在此事件的處理器中設定自訂的 LINQ 運算式。

DynamicFilterExpression

使用指定的 DynamicFilter 控制項建立資料庫查詢,此過濾器只支援 Dynamic Data。

MethodExpression

為資料來源設定使用者自訂的 LINQ 運算式,這個過濾器會在一個方法中被呼叫。

OrderByExpression

在一個支援 IQueryable 的資料來源物件中設定排序過算式,在套用了 OrderByExpression 過濾器後,仍然可以使用 ThenByExpression 加上額外的排序條件。

PropertyExpression

使用 WhereParameters 集合中的參數建立 WHERE 指令。

RangeExpression

決定條件變數的區間,例如大於,小於或是介於兩個數值之間。

SearchExpression

在資料來源的指定欄位中比對出符合條件的資料。

下列的程式碼是使用 QueryExtender 強化查詢選項的範例:

 

<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="DataClassesDataContext"
  EntityTypeName="" 
  Select="new (HomeID, Bedrooms, ImageURL, Price, Available, Description)" 
  TableName="Homes">
</asp:LinqDataSource>
<asp:QueryExtender ID="QueryExtender1" TargetControlID="LinqDataSource1" runat="server"> 
  <asp:OrderByExpression DataField="Price" Direction="Descending"></asp:OrderByExpression> <!-- 排序 -->
  <asp:RangeExpression DataField="Price" MinType="Inclusive" MaxType="Inclusive"><!-- 範圍設定 --> 
    <asp:Parameter DefaultValue="200000" DbType="Int32" />
    <asp:Parameter DefaultValue="750000" DbType="Int32" />
  </asp:RangeExpression>
  <asp:PropertyExpression><!-- 設定指定屬性做過濾 --> 
    <asp:Parameter Name="Available" DefaultValue="True" DbType="Boolean" />
  </asp:PropertyExpression>
  <asp:SearchExpression DataFields="Description" SearchType="Contains"><!-- 檢查欄位中的資料 --> 
    <asp:Parameter DefaultValue="private" DbType="String" />
  </asp:SearchExpression>
</asp:QueryExtender>

 

上面的 QueryExtender 指令會產出下列的 SQL 指令 (配合 Entity Framework Data Source 時):

 

exec sp_executesql 
N'SELECT [t0].[HomeID], 
  [t0].[Bedrooms], 
  [t0].[ImageURL], 
  [t0].[Price], 
  [t0].[Available], 
  [t0].[Description]
FROM 
  [dbo].[Homes] AS [t0]
WHERE 
  ([t0].[Description] LIKE @p0) AND 
    ([t0].[Available] = @p1) AND 
    ([t0].[Price] >= @p2) AND ([t0].[Price] <= @p3)
ORDER BY 
  [t0].[Price] DESC',
N'@p0 nvarchar(4000),@p1 int,@p2 int,@p3 int',
@p0=N'%private%',
@p1=1,
@p2=200000,
@p3=750000

 

QueryExtender 除了可以支援 LinqDataSource 以及 EntityDataSource 外,它也可以和其他第三方軟體開發商的 Data Source 控制項合併使用。

 

2. EnablePersistedSelection 讓已選取的選項不會因為分頁而移動

 

以往如果在 GridView 以及 ListView 控制項中,如果有做分頁的話,若選擇其中一筆資料時,控制項會以當下的 ROW INDEX 來保存哪一列被選取,但是它不會受到翻頁的影響,也就是說就算是翻項了,該 ROW INDEX 的選取狀態會仍然存在,如同下圖的變化:

 

PersistedSelectionFalse1PersistedSelectionFalse2PersistedSelectionFalse3PersistedSelectionFalse4

 

這會讓開發人員還要額外處理選取狀態的變化,否則選取的資料列就會不正確,這個問題似乎可以說是一種 bug,但到了 ASP.NET 4.0,這個問題已經解決,在 ASP.NET 4.0 的 GridView 和 ListView 中,新增了一個 EnablePersistedSelection 屬性,它可以讓 GridView 和 ListView 以資料鍵值 (data-key value) 來保持選取的狀態,因此到了 ASP.NET 4.0,上列的圖會變成這樣:

 

PersistedSelectionTrue1PersistedSelectionTrue2PersistedSelectionTrue3PersistedSelectionTrue4

 

可以看到,ListView 的列選取狀態不會再像原本那樣被列索引鎖死,而是以資料鍵值來維持。

參考資料:

ASP.NET 4.0 Query Extender

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.queryextender(VS.100).aspx