我在使用ObjectDataSource控件在ASP.Net中實現AJax真分頁一文中詳細介紹過如何使用ObjectDataSource和ListView實現數據綁定和分頁功能。事實上,采用ObjectDataSource和ListVIEw相結合,可以減少我們很多的開發任務。
ObjectDataSource在使用時需要事先指定查詢方法SelectMethod(其實還有 InsertMethod,UpdateMethod和DeleteMethod),TypeName和DataObjectTypeName,然後我們只需要編寫好SelectMethod方法的實現,如果需要分頁,那麼還要指定MaximumRwosParameterName屬性和 StartRowIndexParameterName,然後在SelectMethod方法中加上相應的參數,當然,SelectCountMethod屬性也是要指定的,並且參數簽名必須和SelectMethod方法的參數簽名相同。這些我在前面那篇文章中都有詳細的介紹。這裡我想說一下如何動態指定ObjectDataSource對象的查詢參數,例如我們使用ObjectDataSource對象來綁定 ListVIEw數據源,一般查詢參數都是事先通過SelectParameter確定好並傳入給ObjectDataSource的,如果我們想實現根據用戶選擇的條件進行查詢,在頁面回傳的時候將查詢條件傳遞給ObectDataSource對象,並且允許隨意指定查詢參數的數據類型,怎麼實現呢?
其實ObjectDataSource參數是可以指定查詢參數的,它有很多種不同類型的查詢參數,如 ControlParameter,CookieParameter,FormParameter,ProfileParameter,QueryStringParameter,SessionParameter 等。由於不能在ObjectDataSource的SelectMethod方法中引入頁面元素,如文本框的值,下拉列表的值,這是因為 ObjectDataSource在初始化並指定SelectMethod方法時頁面上的其它元素還沒有完成初始化,此時引用頁面上的這些元素將會引發空引用的異常。正確的方法是通過ObjectDataSource的查詢參數來解決此類問題,如我們可以使用QueryStringParameter通過頁面的url來傳遞參數,還可以使用CookieParameter通過客戶端的Cookie傳遞參數,使用SessionParameter通過服務端的Session來傳遞參數。不過這些參數都有問題,QueryStringParameter只能傳遞字符串類型的參數,復雜類型的參數很難實現;CookieParameter收到客戶端CookIE的限制,也不太理想;SessionParameter有些誇張,我不能因為用戶想完成一次簡單的查詢操作就在服務器上存放一大堆Session吧?
看來使用ControlParameter是比較理想的,畢竟用戶都是通過頁面上的控件來指定查詢條件的,而程序也正是通過頁面上的控件才得到用戶所指定的查詢條件的,這個是比較符合邏輯的。下面我們就來看看如何通過ControlParameter來實現ObjectDataSource的查詢參數動態指定。
<ASP:ObjectDataSource ID="DataSource" runat="server" SelectMethod="SelectDatas"
TypeName="MilitaryShopWeb.Admin.SystemConfig.SysLog" DataObjectTypeName="MilitaryShopModel.Log" EnablePaging="True"
MaximumRowsParameterName="maxRows" StartRowIndexParameterName="startIndex" SelectCountMethod="CountAll" DeleteMethod="DeleteData">
<SelectParameters>
<ASP:ControlParameter ControlID="ddlCate" PropertyName="SelectedValue" Name="cate" />
<ASP:ControlParameter ControlID="ddlArea" PropertyName="SelectedValue" Name="area" />
<ASP:ControlParameter ControlID="tbBeginTime" PropertyName="Text" Name="begintime" />
<ASP:ControlParameter ControlID="tbEndTime" PropertyName="Text" Name="endtime" />
</SelectParameters>
</ASP:ObjectDataSource>
給定的代碼不是完整的代碼,因為我在例子中使用的NHibernate作為數據持久層,這樣我不太方便講整個可執行代碼都貼出來,還望大家能諒解!不過從上面的代碼中可以看出,我們可以直接在ObjectDataSource的標記中引入SelectParameters參數列表,將要作為查詢參數的控件依次通過ControlParameter標記給出。其中ControlID為指定的控件ID,PropertyName為控件取值的屬性名稱,Name為參數名稱,這個與SelectMethod中的查詢參數簽名相對應。
下面是服務端代碼。這裡順便給出了DeleteMethod方法的實現,代碼中引入了其它的類庫,讀者只需看明白其中的道理即可!
public List<Log> SelectDatas(int startIndex, int maxRows, string cate, string area, string begintime, string endtime)
{
int itemCount;
int pageIndex = 1;
if (startIndex > 0)
{
pageIndex = (startIndex) / PageSize + 1;
}
LogBll bll = new LogBll();
List<ICriterion> query = new L
ist<ICriterion>();
ICriterion[] expression = null;
if (cate != "-1")
{
query.Add(Restrictions.Eq("Logtype", cate));
}
if (area != "-1")
{
query.Add(Restrictions.Eq("Applicationarea", area));
}
if (begintime != null && begintime.Trim().Length > 0)
{
query.Add(Restrictions.Ge("Logtime", DateTime.Parse(begintime.Trim())));
}
if (endtime != null && endtime.Trim().Length > 0)
{
query.Add(Restrictions.Le("Logtime", DateTime.Parse(endtime.Trim())));
}
if (query.Count > 0)
{
expression = query.ToArray();
}
try
{
List<Log> list = bll.GetProducts(expression, pageIndex, maxRows, out itemCount);
VIEwState["ITEMCOUNT"] = itemCount;
return list;
}
catch (Exception ex)
{
Log log = new Log(LogType.Error.ToString(), ex.Message, DateTime.Now, ApplicationArea.SysLogManage.ToString(), ex.StackTrace);
ApplicationLog.Write(log);
}
return null;
}
public static void DeleteData(Log obj)
{
try
{
LogBll bll = new LogBll();
bll.Delete(obj.Id);
ScriptHelper.ShowMessage("刪除成功!");
}
catch (Exception ex)
{
Log log = new Log(LogType.Error.ToString(), ex.Message, DateTime.Now, ApplicationArea.ProductCategorIEsList.ToString(), ex.StackTrace);
ApplicationLog.Write(log);
ScriptHelper.ShowMessage("刪除失敗!請查看數據庫日志以確定失敗原因。");
}
}
public int CountAll(string cate, string area, string begintime, string endtime)
{
return Convert.ToInt32(VIEwState["ITEMCOUNT"] ?? 0);
}
CountAll的參數簽名必須和SelectDatas的參數簽名相同。在這裡,查詢參數的數據類型是NHibernate的 ICriterion數組,在SelectDatas中首先會判斷指定控件的值是否為空,不為空則構建ICriterion查詢數組,然後將參數傳遞給底層代碼進行數據查詢。在這裡沒有直接引用頁面上的控件,而是通過查詢參數來獲取的值。這樣,當用戶指定查詢或者查看全部數據時,我們幾乎不用做任何事情。
private void RefreshData()
{
lvList.DataSourceID = DataSource.ID;
}
protected void btDoQuery_Click(object sender, EventArgs e)
{
RefreshData();
}
protected void btAll_Click(object sender, EventArgs e)
{
this.ddlArea.SelectedValue = "-1";
this.ddlCate.SelectedValue = "-1";
this.tbBeginTime.Text = string.Empty;
this.tbEndTime.Text = string.Empty;
RefreshData();
}
RefreshData方法只是將ListVIEw的數據源重新指向ObjectDataSource,以實現數據綁定的“刷新”效果。 btDoQuery_Click只需要執行一下RefreshData方法即可,因為頁面上控件的值已經通過ControlParameter查詢參數傳遞給ObjectDataSource了,我們沒有其它的東西需要處理。別忘了!服務器端控件的值在默認情況下是可以回傳的。btAll_Click是查詢全部數據,此時我們只需要將控件中的值清空,然後重新執行RefreshData方法即可。
是不是很簡單啊?其實ObjectDataSource控件的功能還是很強大的,以後綁定頁面數據,尤其是帶有分頁效果時建議多用ObjectDataSource控件,它可以節省很多的開發時間。