前陣子接到一個需求,那個情境整個讓我整個大發火:允許使用者輸入查詢條件,針對已查詢出來的結果再進行查詢。
聽起來是一個很好用的功能,如果查出來的資料有30頁分頁,用這個方式來過濾資料確實是對使用者來說相當方便。
真正讓我發火的是:那個頁面是40多種查詢項目共用的,不同的查詢項目,GridView上產生的欄位會不一樣,而聽到這個需求的時候,我還在考慮是要從資料庫重新拉資料,還是只是把已經抓出來的資料藏在什麼地方,要的時候再拿出來。更重要的是,我聽到這個需求的時候,隔天就要驗收了,而我還一點頭緒也沒有。
順便宣達一下:在開發功能的時候,真的要有人隨時檢視合約和工作項目之間的關聯,真的不要到驗收前才發現有一些該完成的項目沒列在工作項目裡。
--該冷靜一下的分隔線--
時程的關係,當時已經沒有時間再去改寫DAO,讓使用者在操作介面的時候讓系統重新跟資料庫不斷地拉少量資料,所以決定在頁面上動手腳。
不知道從哪時候開始就有聽說過.NET的伺服器元件裡有一個地方可以讓人寫類似SQL的過濾句,又隱約看過DataTable裡有個Select之類的東西,就打算從這方面開始著手。
查了一下又試了一下,發現有點不太容易使用。
DataTable.Select(string expression)中,Select裡可以塞一段類似SQL裡的WHERE條件句的字串,把DataTable裡的資料再做一次過濾(參考expression的寫法)。壞就壞在他回傳的是DataRow陣列,而且還是這個DataTable自己的DataRow,不是另外Create一塊新的DataRow來放,所以也不能把這些DataRow再加到其它的DataTable裡,我要怎麼顯示在介面上都不太對,這個東西就變成練習用的玩具,不算產出。
後來survey各路名門文獻來尋找靈感,就這麼無意間讓我知道由DataTable.DefaultView回傳回來的一個DataView,裡面除了裝著DataTable的資料之外,官方還說可以進行資料的篩選和排序。
是我要的篩選!
於是我就在這個DataView.RowFilter裡加那些原本寫在DataTable.Select裡的expression,再把GridView和DataTable重新Bind一下,就可以得到我要的結果了!
private void SelectDataTable(string keyword) { DataTable dt = (DataTable)ViewState["dtSource"]; if (keyword == "") { dt.DefaultView.RowFilter = ""; ViewState["RowFilter"] = ""; } else { StringBuilder expWhere = new StringBuilder(); foreach (DataColumn col in dt.Columns) { if (col.ColumnName == "SeqID") { continue; } if (col.DataType != typeof(string)) { continue; } expWhere.Append(string.Format("{0} LIKE '%{1}%' OR ", col.ColumnName, keyword)); } dt.DefaultView.RowFilter = ((ViewState["RowFilter"].ToString() != "") ? ViewState["RowFilter"] + " AND " : "") + "(" + expWhere.ToString().Remove(expWhere.Length - 3, 3) + ")"; ViewState["RowFilter"] = dt.DefaultView.RowFilter; } ViewState["dtSource"] = dt; SetGridView(dt); }
老天保佑,It's work!
下面是畫面圖。為保護當事人已馬賽克(?)處理
圖1. 查出來的資料很多,有8頁
圖2. 透過RowFilter來過濾資料
圖3. 再濾一次。這個功能會讓關鍵字查詢用AND的方式把前後的查詢一次一次濾掉,不過這裡看不出來....
Ref:
2 則留言:
剛好 我昨天用到了datatable.defaultview.sort XD
小殺你也寫一篇來教一下啊
張貼留言