动态指定任意类型的ObjectDataSource对象的查询参数


我在使用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 List<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控件,它可以节省很多的开发时间。



相关阅读:
CSS:网页表单实现鼠标悬停交互效果
PHP 字符串加密函数(在指定时间内加密还原字符串,超时无法还原)
Javascript玩转Prototype(二)
怎样设置AHCI来提高Windows 7的系统运行速速
纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等)
非常流行的所谓的气泡窗口
MYSQL教程:优化服务器参数设置
解读css发展历史
asp.net HttpWebRequest自动识别网页编码
JSP技术简介之四
标签参考:前人知名网站H标签的用法
不用GD库生成当前时间的PNG格式图象的程序
js表格分页实现代码
关于ASP生成伪参数技巧 简洁实用的伪(僞)参数
快速导航

Copyright © 2016 phpStudy | 皖ICP备18014864号-4