首页 > 技术文章 > 解决:C#除非指定UpdateCommand,否则数据源SqlDataSource不支持更新操作

zhaolizhe 2017-06-03 11:20 原文

今天在做东西,更新数据库,数据库更新成功了,可是sqldatasource却求支持,于是我找了所有可能的原因,最后终于解决了。就是更新完数据库一定要记得更新sqldatasource!虽然不是什么大错,但是改了,页面才会百分百不出错,看着也舒服些么!下面就是更新它的一个简单举例:

SqlDataSource1.UpdateCommand = "UPDATE PlayList SET PlayTime="+time2+", PlayBorder="+border+"";

下面来看看原因吧:
SqlDataSource控件 

SqlDataSource控件是一个数据源控件,代表与一个关系型数据存储(诸如SQL Server或Oracle或任何一个可以通过OLE DB或ODBC桥梁访问的数据源)的连接。

我们使用两个主要属性建立数据存储的连接:ConnectionString和ProviderName。前一个属性表示连接字符串,包含了打开与底层引擎会话所需的足够信息。后一个属性规定此操作使用的ADO.NET托管提供程序的命名空间。ProviderName属性默认为System.Data.SqlClient,这表示默认的数据存储是SQL Server。例如,要瞄准一个OLE DB提供程序,则使用System.Data.OleDb字符串。

该控件既可以使用数据适配器也可以使用命令对象检索数据。根据我们的选择,获取的数据将被封装到一个DataSet对象或一个数据阅读器中。如下代码片断说明了激活一个绑定到一个SQL Server数据库的SQL数据源控件所需的最少代码:

<asp:SqlDataSource runat="server" ID="MySqlSource" 

    ProviderName='<%$ ConnectionStrings:LocalNWind.ProviderName %>'

    ConnectionString='<%$ ConnectionStrings:LocalNWind %>'

    SelectCommand="SELECT * FROM employees" />

<asp:DataGrid runat="server" ID="grid" DataSourceID="MySqlSource" />

1. SqlDataSource控件的编程接口
表9.10列出的属性组提供了关联的视图类所支持的数据操作。



表9.10 配置数据操作的属性
属性组
描述

DeleteCommand, DeleteParameters,

DeleteCommandType
获得或设置用来删除底层数据存储中的数据行的SQL语句、相关参数以及类型(文本或存储过程)。

FilterExpression, FilterParameters
获得或设置用来创建使用Select命令获取的数据之上的过滤器的字符串(和相关参数)。只有当控件通过DataSet管理数据时才起作用。

InsertCommand, InsertParameters,

InsertCommandType
获得或设置用来在底层数据存储中插入新行的SQL语句、相关参数和类型(文本或存储过程)。

SelectCommand, SelectParameters,

SelectCommandType
获得或设置用来从底层数据存储中获取数据的SQL语句、相关参数和类型(文本或存储过程)。

SortParameterName
获得或设置一个命令的存储过程将用来存储数据的一个输入参数的名称。(这种情况下的命令必须是存储过程。)如果缺少该参数,则会引起一个异常。

UpdateCommand, UpdateParameters,

UpdateCommandType
获得或设置用来更新底层数据存储中的数据行的SQL语句、相关参数和类型(文本或存储过程)。


每个命令属性都是一个字符串,包含将要使用的SQL文本。命令可以有选择地包含关联参数集中列出的参数。托管提供程序及其底层的关系引擎决定SQL要使用的确切语法以及嵌入参数的语法。例如,如果数据源控件指向SQL Server,则命令参数名必须以@symbol为前缀。如果目标数据源是一个OLE DB提供程序,则参数是无名的,用一个?占位符符号标识,并且按位置进行定位。如下代码片断展示了一个更复杂的数据源控件,其中启用了参数化删除和更新命令:

<asp:SqlDataSource runat="server" ID="MySqlSource"

    ConnectionString='<%$ ConnectionStrings:LocalNWind %>'

    SelectCommand="SELECT * FROM employees"

    UpdateCommand="UPDATE employees SET lastname=@lname"

    DeleteCommand="DELETE FROM employees WHERE employeeid=@TheEmp"

    FilterExpression="employeeid > 3">

    <!-- parameters go here -->

</asp:SqlDataSource> 

FilterExpression属性适用的语法与DataView类的RowFilter属性适用的语法相同,而后者又类似于SQL WHERE子句使用的语法。如果FilterExpression需要是参数化的,则可以通过FilterParameters集合指明参数。只有在DataSourceMode设置为DataSet时才能启用过滤功能。

注意    注意过滤器表达式和Select命令上的参数之间的区别。该命令上的参数影响数据存储返回的结果集;而过滤器表达式限制通过Select命令返回的结果集的显示内容。

表9.11详细描述了SqlDataSource类的其他操作属性。该列表没有包括与缓存相关的属性,稍后再介绍这些属性。



表9.11 SqlDataSource类的其他属性
属性
描述

CancelSelectOnNullParameter
指示如果一个参数等于null是否撤销数据检索操作。默认值为true。

ConflictDetection
决定该控件在一次删除或更新操作期间应如何处理数据冲突。在默认情况下,同时发生的变更被覆盖。

ConnectionString
连接到数据库的连接字符串。

DataSourceMode
指示应如何返回数据:通过DataSet还是通过数据阅读器。

OldValuesParameterFormatString
获得或设置一个格式字符串,该格式字符串应用于传递给Delete或Update方法的任何参数的名称。

ProviderName
指示将要使用的ADO.NET托管提供程序的命名空间。


有趣的是,这些属性中有很多映射了实际视图类上定义的相同属性,如前面的图9.10所示。

SqlDataSource对象有几个方法和事件,在大多数情况下所有的数据源组件都有这些方法和事件。其中方法包括Delete, Insert, Select和Update,并且它们是作为底层数据源视图类的对应方法的惟一封装器实现的。这些事件成对存在:Deleting/Deleted、Inserting/Inserted、Selecting/Selected和Updating/Updated,并且在上述方法之前和之后激发。过滤操作的开始通过Filtering事件发出信号。

如前所述,ASP.NET 2.0特有的控件是惟一真正地利用数据源控件的能力的控件。因而,后面两章专门介绍GridView, DetailsView和FormView控件,到时将会看到大量示例代码,它们说明了如何使用SqlDataSource控件进行选择、更新、分页和排序。在本章中,我们将花更多的时间来讨论该控件的其他特征,这些特征特别适合在实际应用中使用。

2. 声明性参数
每个命令属性都有自己的参数集——ParameterCollection集合类的一个实例。ASP.NET 2.0支持不少参数类型,如表9.12所示。

表9.12 ASP.NET 2.0中的参数类型
参数
描述

ControlParameter
从一个服务器控件的任何公共属性获得该参数值。

CookieParameter
根据指定的HTTP cookie的内容设置参数值。

FormParameter
从HTTP请求窗体的指定输入字段中获取该参数值。

Parameter
获取由代码分配的参数值。

ProfileParameter
从根据应用程序的个性化机制创建的配置文件对象中的指定属性获取该参数值。

QueryStringParameter
从请求查询字符串中的指定变量获取该参数值。

SessionParameter
根据指定的会话状态槽的内容设置该参数值。


每个参数类都有一个Name属性以及它的作用和实现特有的属性集。为了理解数据源控件中的声明性参数,让我们看看如下代码:

<asp:SqlDataSource runat="server" ID="MySource"

    ConnectionString='<%$ ConnectionStrings:LocalNWind %>'

    SelectCommand="SELECT * FROM employees WHERE employeeid > @MinID">

    <SelectParameters>

        <asp:ControlParameter Name="MinID" ControlId="EmpID"

            PropertyName="Text" />

    </SelectParameters>

</asp:SqlDataSource> 

该查询包含一个名为@MinID的占位符。该数据源控件用ControlParameter对象返回的信息自动地填充该占位符。控件参数的值由给定控件上的给定属性所决定。PropertyName属性规定了该属性的名称;而该控件的ID在ControlId属性中。为了使前面的代码起作用,页面开发人员必须保证该页面包含一个具有给定的ID和属性的控件;否则,抛出一个异常。在本例中,EmpID控件上的Text属性的值被用作匹配参数的值。

形参(命令文本中的占位符)和实际值之间的绑定,取决于底层的托管提供程序如何处理和辨认参数。如果提供程序类型支持有名的参数(象SQL Server和Oracle那样),则这种绑定涉及将占位符的名称与参数的名称进行匹配。否则,这种匹配是基于位置的。因此,第1个占位符绑定到第1个参数,以此类推。这就是使用OLE DB访问数据时发生的情况。

3. 冲突检测
SqlDataSource控件能够以两种方法之一有选择地执行数据库侵入的操作(删除和更新)。数据源控件与数据绑定控件相联系,因此,同时读取数据,也许还要在客户端进行修改,然后进行更新,这种思想并不是牵强的。在多个用户拥有对数据库的读/写访问的情况下,如果他们企图操作的记录同时被修改了,则更新/删除方法的行为应怎样呢?

SqlDataSource控件使用ConflictDetection属性确定在执行更新和删除操作时要做什么。该属性被声明为ConflictOptions枚举类型;其默认值是OverwriteChanges,这就是说,无论该行中的值自上一次被读取以来有没有发生变化,任何侵入操作都会发生变化。另一个值是CompareAllValues,它只是确保SqlDataSource控件将从数据库读取得原始数据,传给底层视图类的Delete或Update方法。

除非这样编写删除或更新语句,即如果该行中的数据不匹配最初读取的数据,则命令失败,否则改变ConflictDetection的值不会产生任何显著效果,注意到这一点是重要的。为做到这一点,应如下面这样定义命令:

UPDATE employees SET firstname=@firstname

WHERE employeeid=@employeeid AND firstname=@original_firstname

换句话说,我们必须显式地向命令添加一个额外的子句,检查正被修改的字段的当前值是否仍然匹配最初读取的值。这样,多个用户同时输入的中间变更使WHERE子句失败,从而使命令失败。我们自己负责调整命令文本;把ConflictDetection设置为CompareAllValues是不够的。

如何格式化表示旧值的参数的名称?SqlDataSource控件使用OldValuesParameterFormatString属性格式化这些参数名。默认值是original_{0}。

如果使用CompareAllValues选项,则可以处理数据源控件上的Deleted或Updated事件,以检查多少行受到影响。如果该操作没有影响任何记录,则可能会发生并发违规(concurrency violation):

void OnUpdated(object sender, SqlDataSourceStatusEventArgs e)

{

    if (e.AffectedRows == 0) {

    ...

    }

}

4. 缓存行为
一个数据绑定控件与它的数据源组件之间的数据绑定是自动完成的,并在由数据绑定控件引起的每次页面回发时发生。假设一个页面有网格、一个数据源控件和一个按钮。如果以编辑模式打开该网格,则Select命令运行;如果单击该按钮(在数据绑定控件的边界之外),则根据视图状态重建该网格的UI,并且不会运行任何Select语句。

为了在每次回发时保存一个查询,可以要求数据源控件缓存给定期间内的结果集。在数据被缓存的时间里,Select方法从缓存(而不是底层数据库)中检索数据。在该缓存期满时,Select方法从底层数据检索数据,并新数据存回到缓存中。SqlDataSource的缓存行为由表9.13中的属性所控制。

表9.13 SqlDataSource上的缓存属性
属性
描述

CacheDuration
指示数据应当在缓存中保留多久(以秒为单位)。

CacheExpirationPolicy
指示缓存期限是绝对的还是可调整的。如果是绝对的,则在规定的秒数之后使缓存中的数据无效。如果是可调整的,则使那些在指定期限内没有用过的数据无效。

CacheKeyDependency
指示用户定义的缓存键的名称,该缓存键链接到数据源控件创建的所有缓存项。通过终止该键,可以清楚该控件的缓存。

EnableCaching
启用或禁用缓存支持。

SqlCacheDependency
获得或设置一个用分号分隔的字符串,指示哪些数据库和表用于SQL Server缓存依赖。


SelectCommand、ConnectionString和SelectParameters的每种不同组合创建一个缓存项。如果多个SqlDataSource控件正好装载相同数据库中的相同数据,则它们可以共享相同的缓存项。通过CacheKeyDependency属性可以控制由数据源控件管理的缓存项。如果该属性设置为非null字符串,则强制SqlDataSource控件在用户定义的键和该控件创建的所有缓存项之间建立依赖性。这时,要清除该控件的缓存,只需给依赖键分配一个新值:

Cache["ClearAll"] = anyInitializationValue;

SqlDataSource1.CacheKeyDependency = "ClearAll";

...

Cache["ClearAll"] = anyOtherValue;

SqlDataSource控件只有在DataSet模式下工作时才能缓存数据。如果DataSourceMode设置为DataReader,并且缓存被启用,则会得到一个异常。

最后,SqlCacheDependency属性将SqlDataSource控件缓存的数据与指定数据库表(通常与提供缓存数据的表是同一个表)的内容联系起来:

<asp:SqlDataSource ID="SqlDataSource1" runat="server"

CacheDuration="1200"

ConnectionString="<%$ ConnectionStrings:LocalNWind %>"

EnableCaching="true"

SelectCommand="SELECT * FROM employees"

SqlCacheDependency="Northwind:Employees"> 

</asp:SqlDataSource>

推荐阅读