SqlWhereBuilder ASP.NET 服务器控件

分享于 

30分钟阅读

Web开发

  繁體

介绍

SqlWhereBuilder 是一个web控件,它提供了用于生成自定义SQL的用户界面 火警的警铃在哪里? 为了支持即席报表需要,用户通过接口添加条件,开发人员使用 GetWhereClause() 或者 GetWhereClauseWithParameters() 方法在一个适合于在SQL中包含的文本中使用或者方法 火警的警铃在哪里? 子句使用以下注意事项开发 SqlWhereBuilder 控件:

  • 用户交互应该处理客户端,防止对每个条件操作都需要服务器回发。
  • 尽可能利用服务器端通过 ASP.NET. 提供的功能

为了满足前面的考虑,客户端功能被开发为独立的JavaScript库。 使用 IE 和Netscape测试该控件,应该与支持 JavaScript 1.2.document.getElementById() 函数。innerHTML 属性和CSS样式的浏览器一起使用。 显示 的属性 行内 单击以下链接下载客户端JavaScript库

在解决后一种考虑时,该控件通过XML文件支持开发人员配置,并可以通过生成 IDbCommand 文件与类型 火警的警铃在哪里?IDbDataParameter 对象兼容的子句语法。 本文介绍了该控件,描述了开发人员的配置任务,并演示了如何检索 火警的警铃在哪里? 介绍了用于呈现的技术和用于在客户端JavaScript库之间通信的技术和 ASP.NET 服务器端控件。

关于控件

SqlWhereBuilder 用户界面由以下可视元素组成:

  • 条件列表

    条件在用户添加时显示在这里区域中。

  • 字段下拉菜单

    字段下拉列表提供数据库字段的列表;字段的用户选择开始一个条件。

  • 操作员下拉菜单

    当选择字段时,运算符下拉列表提供适合于该字段的比较运算符列表,由开发人员配置。 例如文本字段可以包含运算符" "," 不是 "," 包含 ,and和" 为空 。数字字段可以包含运算符,如" 等于 and" 大于 "。运算符有关联的sqlTemplates,用于将条件转换为适合于SQL的语法 火警的警铃在哪里? 子句。

  • ValueEntry区域

    当选择操作符时,将显示它的关联的ValueEntry区域,为用户提供输入适合运算符的比较值。 ValueEntry区域呈现为 <div> 选择和隐藏作为操作符的客户端上的标记。 ValueEntry区域可能包含文本文本和 HTML ;客户端库支持 <输入> 类型的标记 文本电台广播 以及 <选择> 标签。ValueEntry区域也可以使用 UserControl (. ascx ) 定义,提供控件呈现支持的表单输入。

示例 上面 显示由单个文本框组成的ValueEntry区域。 示例 below 显示了" 介于 ,为 Date 字段定义的运算符,有两个 <输入 type="文本"> ValueEntry区域的标记:

以下示例ValueEntry是从 UserControl 派生的,它使用来自Northwind数据库的雇员姓名填充 DropDownList:

用户通过界面添加条件时,它们会出现在条件列表区域中,其中有删除和编辑按钮,这些按钮位于每个界面的左边。 添加一个条件后,和/或者下拉列表中还会出现一个条件,用户可以选择适合它的条件的SQL连接。

为给定条件单击编辑按钮时,通常位于底部的条目表单将移动以编辑所选条件:

配置

使用 SqlWhereBuilder web控件,开发人员必须将JavaScript库代码文件复制到服务器上的适当位置。 开发人员还必须定义ValueEntry区域。OperatorLists和可以供用户使用的字段。 这通常是通过XML文件完成的。

客户端JavaScript库

web SqlWhereBuilder 控件的所有客户端功能都内置到JavaScript文件 SqlWhereBuilder.js. 中,控件希望该文件在以下位置( 其中wwwroot是服务器的web 根目录 ) 中找到这里文件:

wwwroot/aspnet_client/UNLV_IAP_WebControls/SqlWhereBuilder

将文件 SqlWhereBuilder.js 复制到 上面 文件夹路径,并且它对每个 SqlWhereBuilder 实例都可用。 要为客户端JavaScript文件指定备用位置,请将 SqlWhereBuilder 实例的属性 ClientCodeLocation 设置为( 有关更多信息,请参见控制文档)。

xml 配置文件

除了客户端库的标识之外,SqlWhereBuilder 实例的配置通常通过XML文件进行处理。 配置文件通过属性 ValueEntryFileOperatorListsFileFieldsFile 来标识。 尽管灵活性是为单个文件提供的,但不是严格必要的;所有的配置标记都可以在。

使用 <valueEntry> 标记定义了ValueEntry区域,其中包含以下属性:

  • id - 这里ValueEntry区域的唯一标识符,供运算符参考。
  • UserControl - ( 可选) 为该ValueEntry区域呈现的UserControl (. ascx )的虚拟路径。

这里示例显示一个 定义了四个入口区域的ValueEntryFile: 一个用于单个文本框,一个空白( 对于不需要额外用户输入的运算符),一个用于选择下拉框,一个由外部 UserControl 定义。

<configuration><valueEntryid="onetext"><inputtype="text"id="onetext_1"size="10"/></valueEntry><valueEntryid="blank"><!-- left intentionally blank --></valueEntry><valueEntryid="region"><selectid="region_select1"><optionvalue="N">North</option><optionvalue="S">South</option><optionvalue="E">East</option><optionvalue="W">West</option></select></valueEntry><valueEntryid="customers"userControl="CustomersDropdown.ascx"/></configuration>

在定义ValueEntry区域时,为每个表单输入提供一个 id 属性( 如" onetext_1"用于" onetext"在上面的示例中输入)。 表单输入 id 0 是由操作符的sqlTemplate 属性引用的。 在单选按钮组的情况下, 姓名 属性由 sqlTemplate 引用。

运算符分为 OperatorLists,分别通过 <operator><operatorList> 标记定义。 OperatorList提供了一组适合给定字段的运算符。 OperatorLists可以被认为松散绑定到特定数据类型( 例如文本。数字或者日期数据类型),并为该数据类型的字段提供适当的运算符选择。 例如,定制OperatorLists也可以定义为限制标准数据类型的选择,或者提供适合于 UserControl的ValueEntry区域。 OperatorLists有一个属性:

  • id - 这里OperatorList的唯一标识符,供字段参考。

运算符的定义具有以下属性:

  • id - 这里运算符的唯一标识符。
  • text - 在 SqlWhereBuilder 输入表单中显示操作员的下拉列表。
  • valueEntry - 关联的ValueEntry区域的id ;当从下拉列表中选择这里操作符时,将显示相关的ValueEntry区域。
  • sqlTemplate - 用于定义使用这里运算符的条件如何转换为有效的SQL语法的模板字符串。

sqlTemplate 属性在其他符合条件的条件中使用占位符。 文本占位符 #FIELD# 替换条件中的字段名称。 在ValueEntry区域中的表单输入使用从输入中派生的占位符表示 id 属性( 或者 姓名 属性,在单选按钮组的情况下,使用磅符号( # ) 作为分隔符。 例如如果ValueEntry区域定义了文本输入 id =" onetext_1",sqlTemplate 中的占位符将为 #onetext_1#

在设计 sqlTemplate s: 时,另外一个考虑因素是 火警的警铃在哪里? 子句将作为字符串( 使用 GetWhereClause() 方法) 或者具有参数占位符( 使用 GetWhereClauseWithParameters() 方法)的字符串构造。 如果使用前者,那么 sqlTemplate 中应该包含适当的数据类型( 文本类型的单引号,例如)的分隔符。 如果使用后一种方法,则不需要数据类型分隔符;valueEntry输入占位符将替换为 IDbDataParameter 占位符。 火警的警铃在哪里? 子句。下面的示例演示" 等于 使用前一个方法对文本数据类型进行比较运算符,将单引号合并为文本分隔符:

<operatorid="text_is"text="Is"valueEntry="onetext"sqlTemplate="#FIELD# = '#onetext_1#'"/>

定义与 IDbDataParameter 对象(。GetWhereClauseWithParameters() 方法) 一起使用的运算符将类似于这里( 分隔符没有单引号):

<operatorid="text_is"text="Is"valueEntry="onetext"sqlTemplate="#FIELD# = #onetext_1#"/>

下面的示例显示了一个包含五个列表的OperatorListsFile: 一个用于一般文本数据类型,一个用于布尔条件,一个用于数值数据类型,一个用于区域选择,另一个用于在ValueEntry示例 上面 中定义的"客户"ValueEntry区域。 这些运算符假定 GetWhereClauseWithParameters() 方法将用于编译 火警的警铃在哪里? 子句,因此不使用数据类型分隔符。

<configuration><operatorListid="opList_text"><operatorid="opList_text_is"text="Is"valueEntry="onetext"sqlTemplate="#FIELD# = #onetext_1#"/><operatorid="opList_text_isnot"text="Is Not"valueEntry="onetext"sqlTemplate="#FIELD#!= #onetext_1#"/><operatorid="opList_text_isnull"text="Is Null"valueEntry="blank"sqlTemplate="#FIELD# IS NULL"/></operatorList><operatorListid="opList_boolean"><operatorid="opList_boolean_true"text="Is True"valueEntry="blank"sqlTemplate="#FIELD# = 1"/><operatorid="opList_boolean_false"text="Is False"valueEntry="blank"sqlTemplate="#FIELD# = 0"/><operatorid="opList_boolean_null"text="Is Null"valueEntry="blank"sqlTemplate="#FIELD# IS NULL"/><operatorid="opList_boolean_notnull"text="Is Not Null"valueEntry="blank"sqlTemplate="#FIELD# IS NOT NULL"/></operatorList><operatorListid="opList_numeric"><operatorid="opList_numeric_equals"text="Equals"valueEntry="onetext"sqlTemplate="#FIELD# = #onetext_1#"/><operatorid="opList_numeric_notequals"text="Does Not Equal"valueEntry="onetext"sqlTemplate="#FIELD#!= #onetext_1#"/><operatorid="opList_numeric_gt"text="Is Greater Than"valueEntry="onetext"sqlTemplate="#FIELD# &gt; #onetext_1#"/><operatorid="opList_numeric_lt"text="Is Less Than"valueEntry="onetext"sqlTemplate="#FIELD# &lt; #onetext_1#"/></operatorList><operatorListid="opList_region"><operatorid="opList_region_is"text="Is"valueEntry="region"sqlTemplate="#FIELD# = #region_select1#"/><operatorid="opList_region_isnot"text="Is Not"valueEntry="region"sqlTemplate="#FIELD#!= #region_select1#"/></operatorList><operatorListid="opList_customers"><operatorid="opList_customers_is"text="Is"valueEntry="customers"sqlTemplate="#FIELD# = #customers_ddCustomers#"/><operatorid="opList_customers_isnot"text="Is Not"valueEntry="customers"sqlTemplate="#FIELD#!= #customers_ddCustomers#"/></operatorList></configuration>

字段是通过 <field> 标记定义的,具有以下属性:

  • id - 这里字段的唯一标识符;id 应与数据库中的字段名相同。
  • text - 在 SqlWhereBuilder 输入表单中显示字段下拉列表的文本。
  • operatorList - 关联的OperatorList的id ;当在项表单中选择这里字段时,运算符下拉列表将用 operatorList 定义的运算符组填充。
  • parameterDataType - 使用 GetWhereClauseWithParameters() 方法时要合并的IDbDataParameter 对象的System.Data.DbType ;如果使用 GetWhereClause(),则不必使用这里属性。

以下示例显示了定义了六个字段的FieldsFile,并使用上面定义的operatorLists:

<configuration><fieldid="Text1"text="My First Text Field"operatorList="opList_text"parameterDataType="String"/><fieldid="Bool1"text="My Boolean Field"operatorList="opList_boolean"parameterDataType="Boolean"/><fieldid="Region1"text="My Region"operatorList="opList_region"parameterDataType="String"/><fieldid="Text2"text="My Second Text Field"operatorList="opList_text"parameterDataType="String"/><fieldid="Customer"text="Customer"operatorList="opList_customers"parameterDataType="String"/><fieldid="IntField"text="My Integer Field"operatorList="opList_numeric"parameterDataType="Int16"/></configuration>

使用XML配置文件 prepared,开发人员可以在. aspx 页中声明 SqlWhereBuilder 控件,如下例所示:

<%@RegisterTagPrefix="cc1"Namespace="UNLV.IAP.WebControls"Assembly="SqlWhereBuilder"%><html><head><title>SqlWhereBuilder example</title></head><body><formrunat="server"><h3>SqlWhereBuilder example</h3><cc1:SqlWhereBuilderid="SqlWhereBuilder1"runat="server"FieldsFile="fields.config"OperatorListsFile="operatorLists.config"ValueEntryFile="valueEntry.config"/></form></body></html>

开发者可以通过代码将适当的对象添加到 Collection 属性 ValueEntryDivsoperatorListsFields 中,作为使用XML配置文件的替代方法。 此外,还有一些属性会影响控件的外观,包括按钮标签。CSS类和样式。 有关 SqlWhereBuilder 控件中使用的集合和对象以及外观属性完整列表的更多信息,请参见控制文档。

检索where子句

生成 SQL 火警的警铃在哪里? 从发布的条件集合中,开发人员可以使用 GetWhereClause() 或者 GetWhereClauseWithParameters() 方法。 返回使用运算符的sqlTemplate 属性编译的每个提供条件的sql语法字符串。 返回不带单词的字符串" 火警的警铃在哪里? "允许使用灵活性。

GetWhereClause() 方法

这里方法返回 火警的警铃在哪里? 子句作为纯字符串,并假定在运算符的sqlTemplate 属性中嵌入了正确的数据类型分隔符(。字符类型的单引号)。 请注意,这里方法可能很容易受到SQL注入类型攻击。 尽管控件尝试为每个提交的值调用它的ValidateValue() 方法,但开发人员可以能希望在返回的字符串中执行自己的验证。 ValidateValue() 方法定义为 虚拟 允许开发人员在需要时重写这里方法。

GetWhereClauseWithParameters() 方法

这是推荐的方法,当目的是生成 火警的警铃在哪里?IDbCommand 对象( 例如 SqlCommand 或者 OleDbCommand ) 一起使用的子句。 这里命令编译 火警的警铃在哪里? 子句具有适合特定 IDbCommand 实现的参数占位符,并将类型特定的IDbDataParameter 对象添加到 IDbCommand。 下面的示例演示如何检索 火警的警铃在哪里? 基于用户提供条件的子句,响应按钮单击提交。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 火警的警铃在哪里? 子句的参数添加到 OleDbCommand 对象中,然后执行。

privatevoid Button1_Click(object sender, System.EventArgs e)
{
 OleDbConnection con = null;
 OleDbCommand cmd = null;
 OleDbDataAdapter da = null;
 DataSet ds = new DataSet();
 try {
 // GetConnection() is a method defined elsewhere which // returns an OleDbConnection object con = GetConnection();
 cmd = new OleDbCommand("SELECT * FROM MyTable", con);
 // inspect the SqlWhereBuilder.Conditions property to see if any// conditions were suppliedif (SqlWhereBuilder1.Conditions.Count >0)
 {
 // retrieve the WHERE clause and add parameters to the // OleDbCommand objectstring sWhere = SqlWhereBuilder1.GetWhereClauseWithParameters(cmd);
 // add the WHERE clause to the command text; we could throw // in additional WHERE clause criteria here if we wanted cmd.CommandText += " WHERE" + sWhere;
 }
 // execute the query da = new OleDbDataAdapter(cmd);
 da.Fill(ds);
 // bind results to a datagrid on the page dgResults.DataSource = ds;
 dgResults.DataBind();
 }
 catch (Exception ex)
 {
 // do something with exceptions... }
 finally {
 if (ds!= null) ds.Dispose();
 if (da!= null) da.Dispose();
 if (cmd!= null) cmd.Dispose();
 if (con!= null) con.Dispose();
 }
}

GetWhereClauseWithParameters() 方法自动为 SqlCommandOleDbCommandOdbcCommand 对象生成适当的占位符。 有关使用 GetWhereClauseWithParameters() 和其他 IDbCommand 类型的其他说明,请参阅控制文档。

呈现

SqlWhereBuilder 控件的实际呈现通过客户端JavaScript函数进行。 在这种情况下,基于覆盖的服务器方法 OnPreRenderRender 工作通过调用 Page.RegisterStartupScript()Page.RegisterClientScriptBlock() 来生成和输出适当的客户端脚本。 例程遍历所有字段和操作符对象,注册客户端库期望的JavaScript代码来初始化 SqlWhereBuilder 对象。

重写的OnPreRender 还调用方法 PrepareValueEntryDivs()。 这里方法解释ValueEntry对象的内部 Collection,以确定哪些是文本/文本,哪些是由 UserControl 对象派生的。 然后,每个都成为 SqlWhereBuilder 对象的子控件,并通过重写的Render 方法输出到客户端。

客户端/服务器通信条件

SqlWhereBuilder 中任何现有条件都是通过向客户端JavaScript函数 AddCondition() 注册调用来呈现的。 这将成为维护服务器回发之间条件状态的关键元素。 同样,由于在客户端完全操作条件,我们需要一种方法来将一组条件返回到服务器。 在这种情况下,普通的ViewState 机制不能帮助我们。 如果尝试修改隐藏 __VIEWSTATE <input> 标记客户端,则会在服务器上引发异常,服务器认为它的ViewState机制已经破坏了服务器。

解决方案是呈现我们自己的隐藏 <input> 标记,以便将条件集与服务器通信。 每次修改。添加或者删除条件时,客户端方法 UpdateConditionsDisplay() 都会被调用,但在纯JavaScript环境中不必要:

this.hiddenConditionsXml.value = escape(this.SerializeConditions());

引用 this.hiddenConditionsXml 是我们将查询服务器端的隐藏表单输入。 SerializeConditions() 客户端方法生成一个表示条件 Collection的XML字符串:

function SQLWB_SqlWhereBuilder_SerializeConditions()
 {
 var sXml = "<conditions>";
 for (var i=0; i<this.conditions.length; i++)
 {
 sXml = sXml + this.conditions[i].Serialize();
 }
 sXml = sXml + "</conditions>";
 return sXml;
 }

SQLWB_Condition 客户端对象定义它的Serialize() 方法,如下所示:

function SQLWB_Condition_Serialize()
 {
 var sXml = "<condition" + " field="" + this.field.id + """ + " operator="" + this.operator.id + """ + " andOr="" + this.andOr + """ + ">" + "<values>";
 for (var i=0; i<this.values.length; i++)
 {
 sXml = sXml + this.values[i].Serialize();
 }
 sXml = sXml + "</values></condition>";
 return sXml;
 }

然后,通过客户端对象 SQLWB_Value 将单个值(。通过ValueEntry区域中的表单输入输入) 序列化为 <value> 标记:

function SQLWB_Value_Serialize()
{
 var sXml ="<valuename=""+this.name+"""+"value=""+this.value.replace(/"/g,'&quot;')+"""+"friendlyValue=""+this.friendlyValue.replace(/"/g,'&quot;')+""/>";
 return sXml;
}

最终结果是当条件改变客户端时,使用 <condition> 标记的适当XML字符串重新填充隐藏的表单输入。

对于它的部分,SqlWhereBuilder 服务器控件用 IPostBackDataHandler 接口标记。 它通过为 LoadPostData() 方法提供以下代码来完成该约定。 这里代码检查在隐藏表单输入中提供的XML,并反序列化条件的Collection。

publicbool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
 // get the conditions passed in through the hidden fieldstring sHidden = this.GetID(kHIDDEN_CONDITIONS);
 string sData = postCollection[sHidden];
 // the data is escaped on the client end; decode it here sData = this.Page.Server.UrlDecode(sData);
 // treat it like a real Xml document and deserialize from there XmlDocument x = new XmlDocument();
 x.LoadXml(sData);
 SqlWhereBuilderConditionCollection cNew 
 = new SqlWhereBuilderConditionCollection(x.DocumentElement);
 // test if the conditions have changed; this will let us// fire the ConditionsChanged event laterbool retValue =!(this.Conditions.Equals(cNew));
 this.Conditions = cNew;
 return retValue;
}

客户端代码通过隐藏表单输入和XML文本字符串将它的条件集传递给服务器端代码。 服务器端代码通过向客户端函数 AddCondition() 注册调用来向客户端呈现它的条件的Collection。 通过这种往返通信,在服务器回发之间保持状态状态,而不会损坏 ASP.NET's 视图。

摘要

SqlWhereBuilder 控件为用户输入即席查询条件提供了友好的界面,可以将它的编译到SQL中,并将它的保存到数据库中。 火警的警铃在哪里? 子句作为 ASP.NET 服务器控件包装JavaScript库,用户交互完全发生在客户端,而在服务器上,则实现了基于xml的配置和与 IDbCommand 对象集成的附加功能。 一条直线 火警的警铃在哪里? 带有嵌入类型分隔符和文本值的子句是通过 GetWhereClause() 方法生成的。 要集成 火警的警铃在哪里? 子句字符串,使用 IDbCommand 对象,则使用 GetWhereClauseWithParameters() 方法。 后一种方法是首选方法,因为它可以减轻sql注入攻击的可能性。

客户端库负责显示控件时,服务器端呈现方法将 valueEntry 区域输出为 <div> 标记和 register 适当的客户端函数调用。 通过隐藏表单输入将条件状态维护到服务器之间,客户端代码将条件序列化为XML表示。 这里字符串然后在 LoadPostData() 方法中反序列化到服务器上。 总之,SqlWhereBuilder web控件为开发 ad hoc报表应用程序提供了一个工具。


Server  控制  asp  asp-net  
相关文章