本文档是 Visual C# 教程 (切换到 Visual Basic 教程)

在前一篇教程中,我们探讨了 ObjectDataSource 控件如何插入、更新和删除数据。SqlDataSource 控件支持相同的操作,但是方法却截然不同,本教程将探讨如何配置 SqlDataSource,完成插入、更新和删除数据的操作。

« 前一篇教程  |  下一篇教程 »

简介

正如在数据插入、更新和删除概述 中讨论的那样,GridView 控件提供内置的更新和删除功能,而DetailsView 和 FormView 控件则包含对插入、编辑和删除功能的支持。这些数据修改功能无需编写任何代码,可直接嵌入数据源控件。数据插入、更新和删除概述 中探讨了如何使用 ObjectDataSource 通过 GridView 、DetailsView 和 FormView 控件完成插入、更新和删除功能。或者,可使用SqlDataSource 代替 ObjectDataSource 。

回想一下,要使 ObjectDataSource 支持插入、更新和删除功能,我们需要指定完成插入、更新和删除操作调用的目标层方法。使用SqlDataSource ,我们需要提供要执行的 INSERT 、UPDATE 、 和DELETE SQL 语句(或存储过程)。正如我们将在本教程中所看到的,这些语句可手动创建,也可以由 SqlDataSource 的 Configure Data Source 向导自动生成。

注意:由于我们已经讨论了 GridView 、DetailsView 和 FormView 控件的插入、编辑和删除功能,本教程将更多的关注配置 SqlDataSource 控件来支持这些操作。如果您需要温习在GridView 、DetailsView 和 FormView 内的这些功能,请返回编辑、插入和删除数据教程,首先从数据插入、更新和删除概述 开始。

步骤1 :指定 INSERT 、UPDATE 和 DELETE 语句

正如我们在前面两个教程中所看到的,要想从SqlDataSource 控件检索数据,我们需要设置两个属性 :

  1. ConnectionString ,用于指定向哪个数据库发送查询。
  2. SelectCommand ,用于指定返回结果需要执行的 ad-hoc SQL 语句或者存储过程名称。

对于带参数的SelectCommand 值来说,参数值可通过SqlDataSource 的 SelectParameters 集合指定,可包含固定赋值、公用参数源值(查询字符串字段、会话变量、Web 控件值等),或者通过编码分配。调用 SqlDataSource 控件的 Select() 方法时(既可以通过编码调用,也可以从 Web 数据控件自动调用),将建立连接到数据库的连接,将参数值分配给查询,并且将命令转到数据库。根据控件的DataSourceMode 属性值,结果随后可能作为 DataSet 返回,也可能作为 DataReader 返回。

SqlDataSource 控件不仅可以选择数据,还可以采用完全相同的方式,通过支持INSERT 、UPDATE 和 DELETE SQL 语句用于插入、更新和删除数据。只需分配要执行的INSERT 、UPDATE 和 DELETE SQL 语句的InsertCommandUpdateCommandDeleteCommand 属性。如果语句带有参数(它们中大大多数均带有参数),请将它们包含到InsertParametersUpdateParametersDeleteParameters 集合中。

一旦指定了InsertCommand 、UpdateCommand 或DeleteCommand 值,相应的 Web 数据 控件的智能标记中的 “Enable Inserting” 、“Enable Editing” 或者 “Enable Deleting” 将变为可用选项。为了说明这一点,我们需要从 Querying.aspx 页面中举一个在使用 SqlDataSource 控件查询数据 教程中创建的例子,并将其扩充为包含删除能力。

首先,从SqlDataSource 文件夹中打开 InsertUpdateDelete.aspx 页面和Querying.aspx 页面。在 Querying.aspx 页面的设计器上,从 第一个示例中选择 SqlDataSource 和 GridView(ProductsDataSource 和 GridView1 控件)。选择两个控件之后,转到 Edit 菜单,并选择 Copy (或者按下 Ctrl+C )。接下来,转到InsertUpdateDelete.aspx 页面上的设计器,并粘贴到控件中。在将两个控件移动到InsertUpdateDelete.aspx 之后,请在浏览器中测试页面。将在 Products 数据库表中看到所有记录的 ProductID 、 ProductName 和 UnitPrice 值。

图1 :按 ProductID 的顺序列出所有产品

添加 SqlDataSource 的DeleteCommand 和DeleteParameters 属性

此时,我们已经获得了从Products表返回所有记录的SqlDataSource ,以及显示此数据的 GridView 。我们的目标是将此示例扩展为用户可以通过 GridView 删除产品。要完成此目标,我们需要指定SqlDataSource 控件的 DeleteCommand 和DeleteParameters 属性值,然后将GridView 配置为支持删除。

DeleteCommand 和 DeleteParameters 属性可通过多种方式指定:

  • 通过声明式语法指定
  • 从设计器中的 Properties 窗口指定
  • 从Configure Data Source 向导的“Specify a custom SQL statement or stored procedure" 屏幕指定
  • 从Configure Data Source 向导的“Specify columns from a table of view” 屏幕中的Advanced 按钮来指定,实际上,它将自动生成DeleteCommand 和 DeleteParameters 属性中使用的 DELETE SQL 语句和参数集

下面,我们将探讨如何在步骤2 中自动创建 DELETE 语句。现在,尽管 Configure Data Source 向导或者声明式语法选项均可工作,但我们将在设计器中使用 Properties 窗口。

在InsertUpdateDelete.aspx 页面中的设计器中,单击 ProductsDataSource SqlDataSource ,随后屏幕上将显示 Properties 窗口(从 View 菜单选择Properties 窗口,或者单击F4 )。选择 DeleteQuery 属性,屏幕上将显示省略号。

图2 :从 Properties 窗口选择 DeleteQuery 属性

注意:SqlDataSource 没有 DeleteQuery 属性。并且,DeleteQuery 是 DeleteCommand 和 DeleteParameters 属性的组合,仅在使用 设计器 查看窗口Properties 窗口时才被列出。如果您的 Source 视图中查看 Properties 窗口,您会看到 DeleteCommand 属性。

DeleteQuery 属性中单击省略号,屏幕将显示Command and Parameter Editor 对话框(见图 3)。在此对话框中,您可以指定DELETE SQL 语句和参数。在DELETE 命令文本框中输入下列查询(既可以手动输入,也可以使用Query Builder 输入,如果您愿意的话)。

DELETE FROM Products WHERE ProductID = @ProductID

接下来,单击 Refresh Parameters 按钮,向下面的参数列表中添加 @ProductID 参数。

图3 :从 Properties 窗口选择 DeleteQuery 属性

请不要为此参数赋值(保留其参数源为 “None” )。一旦我们给 GridView 提供了删除支持,GridView 将自动支持此参数值,单击 Delete 按钮的行将使用其 DataKeys 集合的值。

注意:DELETE 查询中使用的参数名称必须与 GridView 、DetailsView 或者FormView 中的 DataKeyNames 值的名称一致。也就是说,DELETE 语句中的参数是特意命名为 @ProductID (而不是 @ID),因为 Products 表中关键字列名称(所以,GridView 中的 DataKeyNames 值)为 ProductID 。

如果参数名称和 DataKeyNames 值不匹配,GridView 将无法从 DataKeys 连接自动分配参数值。

在 Command and Parameter Editor 对话框中输入删除相关的信息之后,单击OK ,转到Source 视图,查看结果的声明标记:

<asp:SqlDataSource ID="ProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]"
    DeleteCommand="DELETE FROM Products WHERE ProductID = @ProductID">
    <DeleteParameters>
        <asp:Parameter Name="ProductID" />
    </DeleteParameters>
</asp:SqlDataSource>

请注意添加DeleteCommand 属性、<DeleteParameters> 部分和名为productID 的参数对象。

配置 GridView 启用删除

添加DeleteCommand 属性之后,GridView 的智能标记将包含 “Enable Deleting” 选项。继续执行,并选中此复选框。正如在插入、更新和删除概述 中讨论的一样,这将使GridView 添加一个CommandField ,其 ShowDeleteButton 属性被设置为 True 。如图 4 所示,当页面通过浏览器访问时,页面上将包含一个 Delete 按钮。可以通过删除某些产品来测试此页面。

图4 :每个GridView 行均包含一个Delete 按钮

单击Delete 按钮时出现回传,GridView 为每个单击 Delete 按钮行的 ProductID 参数赋值为 DataKeys 集的值,并调用 SqlDataSource 的 Delete() 方法。然后,SqlDataSource 控件将连接到数据库,并执行DELETE 语句。这样,GridView 将重新绑定到 SqlDataSource ,恢复并显示当前产品(这些产品现在不再包含刚刚删除的记录)。

注意:由于 GridView 使用其 DataKeys 集合为SqlDataSource 参数赋值,因此 GridView 的 DataKeyNames 属性可设置为组成主键的列并且 SqlDataSource 的 SelectCommand 返回这些列就变得至关重要。此外,SqlDataSource 的 DeleteCommand 中的参数名设置为 @ProductID 也十分重要。如果未设置 DataKeyNames 属性,或者参数未命名为 @ProductsID ,单击 Delete 按钮将导致回传,但实际上不会删除任何记录。

图5 以图形方式说明了此过程。有关在 Web 数据控件中与插入、更新和删除相关的事件链的更详细讨论,请参照探讨与插入、更新、删除相关的事件 教程。

图5 : 在 GridView 中单击 Delete 按钮将调用 SqlDataSource 的 Delete() 方法

步骤2 :自动生成 INSERT 、UPDATE 和 DELETE 语句

正如步骤1 中所讨论的,INSERT 、UPDATE 和 DELETE SQL 语句可通过Properties 窗口或者控件的声明式语法指定。但是,此方法要求我们手动编写 SQL 语句,这些语句可能十分单调,并且容易产生错误。幸运的是 ,Configure Data Source 向导提供了一个选项 , 使用 “ Specify columns from a table of view” 屏幕时可自动生成 INSERT 、UPDATE 和 DELETE 语句。

下面,我们探讨一下这个自动生成选项。在InsertUpdateDelete.aspx 中向 设计器 添加一个 DetailsView ,并将其 ID 属性设置为 ManageProducts 。接下来,从 DetailsView 的智能标记中选择创建新数据源,并创建一个名为 ManageProductsDataSource 的 SqlDataSource 。

图6 :创建一个名为 ManageProductsDataSource 的新 SqlDataSource

从Configure Data Source 向导选择使用NORTHWINDConnectionString 连接字符串,单击 Next 。从 “Configure the Select Statement” 屏幕,保留 “Specify columns from a table or view” 单选按钮选中不变,并从下拉列表选择 Products 表。从复选框列表选择 ProductID 、 ProductName 、 UnitPrice 和 Discontinued 列。

图7 :使用 Products 表,返回 ProductID 、ProductName 、UnitPrice 和 Discontinued 列

要根据所选的表和列自动生成 INSERT 、UPDATE 和 DELETE 语句,单击Advanced 按钮,选中 “Generate INSERT, UPDATE, and DELETE statements” 复选框。

图8 :选中 “Generate INSERT, UPDATE, and DELETE statements” 复选框

只有在所选的表有主键并且主键列包含在返回列的列表中时,“Generate INSERT, UPDATE, and DELETE statements” 复选框才可被选中。在选中 “ Generate INSERT, UPDATE, and DELETE statements” 复选框的情况下,“ Use optimistic concurrency” 复选框将作为结果产生的 UPDATE 和 DELETE 语句中增加 WHERE 子句,提供开放式并发控件。现在,不选中此复选框;我们将在下一篇教程中探讨使用 SqlDataSource 控件完成开放式并发。

在选中“Generate INSERT, UPDATE, and DELETE statements” 复选框之后,单击OK 返回 “Configure Select Statement” 屏幕,然后单击 Next ,最后单击 Finish ,完成 Configure Data Source 向导。完成向导后,Visual Studio 将为 ProductID 、ProductName 和 UnitPrice 向 DetailsView 添加BoundFields ,还将为 Discontinued 列添加CheckBoxField 。为了使正在访问此页面的用户能够查看产品,请从DetailsView 的智能标记选择 “Enable Paging” 选项。同时,清除DetailsView 的 Width 和 Height 属性。

请注意,智能标记还提供了 “Enable Inserting” 、“Enable Editing” 和 “Enable Deleting” 选项。这是由于 SqlDataSource 控件包含其 InsertCommand 、UpdateCommand 和 DeleteCommand 值,如下列声明式语法所示:

<asp:DetailsView ID="ManageProducts" runat="server" AllowPaging="True"
    AutoGenerateRows="False" DataKeyNames="ProductID"
    DataSourceID="ManageProductsDataSource" EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
            SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="ManageProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    DeleteCommand=
        "DELETE FROM [Products] WHERE [ProductID] = @ProductID"
    InsertCommand=
        "INSERT INTO [Products] ([ProductName], [UnitPrice], [Discontinued])
         VALUES (@ProductName, @UnitPrice, @Discontinued)"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
         FROM [Products]"
    UpdateCommand=
        "UPDATE [Products] SET [ProductName] = @ProductName,
         [UnitPrice] = @UnitPrice, [Discontinued] = @Discontinued
         WHERE [ProductID] = @ProductID">
    <DeleteParameters>
        <asp:Parameter Name="ProductID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="ProductID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
    </InsertParameters>
</asp:SqlDataSource>

请注意SqlDataSource 控件如何自动设置其InsertCommand 、UpdateCommand 和  DeleteCommand 属性值。InsertCommand 和 UpdateCommand 属性中引用的列是由SELECT 语句中的列决定的。也就是说,InsertCommand 和UpdateCommand 只含有那些SelectCommand 中指定的列,并不是每个Products 列均在InsertCommand 和UpdateCommand 中(由于它是编辑时无法更改它的值,插入时自动分配,将忽略较小的 ProductID )。此外,对于InsertCommand、UpdateCommand 和DeleteCommand 属性中的每个参数来说,InsertParameters 、UpdateParameters 和 DeleteParameters 集合中有相应的参数。

要启用DetailsView 的数据修改功能,请在其智能标记中选中 “Enable Inserting” 、“ Enable Editing” 和 “Enable Deleting” 选项。这将添加一个 CommandField ,其ShowInsertButton 、ShowEditButton 和ShowDeleteButton 属性均被设置为 True 。

在浏览器中访问页面,请注意DetailsView 中包含的 Edit 、Delete 和 New 按钮。单击 Edit 按钮,DetailsView 将切换到编辑模式,该模式将所有ReadOnly 属性被设置为False(默认值)的 BoundField 显示为一个文本框,而 CheckBoxField 则显示为复选框。

图9 :DetailsView 的默认编辑界面

与此类似,您可以删除当前选择的产品,或者向系统添加一个新产品。由于 InsertCommand 语句处理 ProductName 、UnitPrice 和 Discontinued 列,其它列在插入时要么由数据库分配 NULL 值,要么分配它们的默认值。就像 ObjectDataSource 一样,如果 InsertCommand 丢失了任何不允许使用NULL 值或者没有默认值的数据库列表行,尝试执行 INSERT 语句时将出现一个 SQL 错误。

注意:DetailsView 的插入和编辑界面缺少某种定制或验证。要添加validation 控件或定制界面,您需要将BoundFields 转换为TemplateFields 。更多信息 , 请参阅为编辑与插入界面添加验证控件自定义数据修改界面教程。

此外,请记住对于更新和删除来说,DetailsView 使用当前产品的 DataKey 值,此值仅在 DataKeyNames 已经配置完毕的情况下呈现。如果编辑和删除看上去似乎没有效果,请确定是否设置了DataKeyName 属性。

自动生成 SQL 语句的限制

由于“Generate INSERT, UPDATE, and DELETE statements” 仅在从表中选择列时可用,对于更复杂的查询来说,您必须像步骤1 一样编写您自己的INSERT 、UPDATE 和 DELETE 语句。通常情况下,为了实现显示的目的,SQL SELECT 语句使用 JOIN 从一个或者更多个查找表中取回数据(例如,在显示产品信息时取回 Categories 表的 CategoryName 字段)。同时,我们可能想让用户可以编辑、更新或插入数据到“核心”表(此时是 Products 表)。

由于INSERT 、UPDATE 和 DELETE 语句可手动输入,请考虑下列节省时间的技巧。首先,安装SqlDataSource ,保证它可以从 Products 表撤回数据。请使用 Configure Data Source 向导的 “ Specify columns from a table or view” 屏幕,保证可以自动生成 INSERT 、UPDATE 和 DELETE 语句,然后,在完成向导之后,从Properties 窗口选择配置SelectQuery (或者,返回 Configure Data Source 向导,但是使用“Specify a custom SQL statement or stored procedure” 选项。)最后,更新 SELECT 语句,使之包含 JOIN 语法。此技术可以自动生成 SQL 语句,可提供更容易定制的 SELECT 语句,从而节省时间。

自动生成INSERT 、UPDATE 和 DELETE 语句的另外一个限制是 INSERT 和 UPDATE 语句中的列是根据 SELECT 语句返回的列确定的。我们可能需要更新或者插入更多或者更少的字段。例如,来自步骤2 的例子中,我们可能将 UnitPrice BoundField 设置为只读。在这种情况下,它不应该在UpdateCommand 中出现。或者,我们可能希望设置 GridView 中不出现的表字段。例如,添加新记录时,我们可能希望将 QuantityPerUnit 设置为“TODO” 。

如果需要这样的定制,您需要手动完成,要么通过Properties 窗口、向导中的 “Specify a custom SQL statement or stored procedure” 选项完成,要么通过声明式语法完成。

注意:在 Web 数据控件中添加不含有相应字段的参数时,请记住这些参数值在某些方面需要分配值。分配的值可以为:InsertCommand 或 UpdateCommand 中的直接赋值;可从某些预定义源获得(查询字符串 、会话变量、页面上的 Web  控件等);或者可通过编码赋值,正如我们在前面的教程中看到的一样。

小结

为了使Web 数据控件能够使用它们内置的插入、编辑和删除功能,它们绑定的数据源控件必须提供这样的功能。对SqlDataSource 来说,这意味着INSERT 、UPDATE 和 DELETE SQL 语句必须分配给 InsertCommand 、UpdateCommand 和 DeleteCommand 属性。这些属性及其相应的参数集可以手动添加,或者通过Configure Data Source 向导自动生成。在本教程中,我们对上述两种方法均进行了讨论。

实现开放式并发 教程中,我们探讨了通过 ObjectDataSource 使用开放式并发。SqlDataSource 控件也可提供开放式并发支持。如步骤2 所述,自动生成 INSERT 、UPDATE 和 DELETE 语句时,向导将提供 “ Use optimistic concurrency” 选项。正如下一篇教程中我们将看到的,通过 SqlDataSource 使用开放式并发在 UPDATE 和 DELETE 语句中将修改 WHERE 子句,保证页面上次显示数据之后其它列的值均未发生变化。

快乐编程!

 

 

下一篇教程