作者 :斯科特·米切尔
在前面的教程中,我们了解了 ObjectDataSource 控件如何允许插入、更新和删除数据。 SqlDataSource 控件支持相同的作,但方法不同,本教程演示如何配置 SqlDataSource 以插入、更新和删除数据。
介绍
如 插入、更新和删除概述中所述,GridView 控件提供内置的更新和删除功能,而 DetailsView 和 FormView 控件包括插入支持以及编辑和删除功能。 这些数据修改功能可以直接插入数据源控件,而无需编写一行代码。 插入、更新和删除概述 通过使用 ObjectDataSource 来检验如何使用 GridView、DetailsView 和 FormView 控件进行插入、更新和删除。 或者,可以使用 SqlDataSource 代替 ObjectDataSource。
回想一下,为了支持使用 ObjectDataSource 进行插入、更新和删除,我们需要指定要调用的对象层方法来执行插入、更新或删除作。 使用 SqlDataSource,我们需要提供INSERT
和 UPDATE
DELETE
SQL 语句(或存储过程)来执行。 如本教程所示,这些语句可以手动创建,也可以由 SqlDataSource 的“配置数据源”向导自动生成。
注释
由于我们已经讨论了 GridView、DetailsView 和 FormView 控件的插入、编辑和删除功能,本教程将重点介绍如何配置 SqlDataSource 控件以支持这些作。 如果需要在 GridView、DetailsView 和 FormView 中实现这些功能,请返回到“编辑”、“插入”和“删除数据”教程,从 “插入、更新和删除概述”开始。
步骤 1:指定 INSERT、UPDATE 和 DELETE 语句
如前两篇教程所示,若要从 SqlDataSource 控件检索数据,需要设置两个属性:
-
ConnectionString
,指定要向其发送查询的数据库,以及 -
SelectCommand
,它指定要执行的即席 SQL 语句或存储过程名称以返回结果。
对于 SelectCommand
具有参数的值,参数值是通过 SqlDataSource 集合 SelectParameters
指定的,可以包括硬编码的值、常见的参数源值(查询字符串字段、会话变量、Web 控件值等),也可以以编程方式分配。 当以编程方式或自动从数据 Web 控件调用 SqlDataSource 控件 Select()
方法时,将建立与数据库的连接,参数值将分配给查询,并且命令将传送到数据库。 然后,将结果作为数据集或 DataReader 返回,具体取决于控件属性 DataSourceMode
的值。
除了选择数据之外,SqlDataSource 控件还可以通过提供 INSERT
和 UPDATE
SQL 语句的方式插入、更新和 DELETE
删除数据。 只需将InsertCommand
、UpdateCommand
和DeleteCommand
属性分配给要执行的INSERT
、UPDATE
和DELETE
SQL 语句。 如果语句通常具有参数,请将它们包含在InsertParameters
、UpdateParameters
和DeleteParameters
集合中。
指定“InsertCommand
UpdateCommand
DeleteCommand
启用插入”、“启用编辑”或“启用删除”选项后,相应的数据 Web 控件智能标记中的“启用插入”、“启用编辑”或“启用删除”选项将变为可用。 为了说明这一点,让我们从 Querying.aspx
使用 SqlDataSource 控件教程在查询数据 中创建的页面获取一个示例,并对其进行扩充以包含删除功能。
首先从SqlDataSource
文件夹中打开InsertUpdateDelete.aspx
和Querying.aspx
页面。 从 Querying.aspx
页面上的设计器处,选择第一个示例中的 SqlDataSource 和 GridView 这两个控件(即 ProductsDataSource
和 GridView1
控件)。 选择两个控件后,转到“编辑”菜单,然后选择“复制”(或只需按 Ctrl+C)。 接下来,转到 InsertUpdateDelete.aspx
设计器,并粘贴控件。 在你将两个控件移到InsertUpdateDelete.aspx
之后,在浏览器中测试页面。 您应该看到Products
数据库表中所有记录的ProductID
、ProductName
和UnitPrice
列的值。
图 1:列出所有产品,按顺序排序 ProductID
(单击以查看全尺寸图像)
添加 SqlDataSource 的 DeleteCommand 和 DeleteParameters 属性
此时,我们有一个 SqlDataSource,它只返回表中的所有记录 Products
和呈现此数据的 GridView。 我们的目标是扩展此示例,以允许用户通过 GridView 删除产品。 为此,我们需要为 SqlDataSource 控件 DeleteCommand
和 DeleteParameters
属性指定值,然后将 GridView 配置为支持删除。
DeleteCommand
和DeleteParameters
属性可以通过多种方式指定:
- 通过声明性语法
- 在设计器中的“属性”窗口中
- 从“配置数据源”向导中的“指定自定义 SQL 语句或存储过程”界面
- 通过“配置数据源向导”中的“指定列的视图表”屏幕上的“高级”按钮,可以自动生成用于
DeleteCommand
和DeleteParameters
属性的DELETE
SQL语句和参数集合。
我们将研究如何在步骤 2 中自动创建 DELETE
语句。 现在,让我们在设计器中使用“属性”窗口,尽管“配置数据源”向导或声明性语法选项同样可行。
在设计器中 InsertUpdateDelete.aspx
,单击 ProductsDataSource
SqlDataSource,然后打开“属性”窗口(在“视图”菜单中,选择“属性”窗口,或直接点击 F4)。 选择 DeleteQuery 属性,该属性将引发一组省略号。
图 2:从“属性”窗口中选择 DeleteQuery 属性
注释
SqlDataSource 没有 DeleteQuery 属性。 相反,DeleteQuery 是DeleteCommand
和DeleteParameters
属性的组合,仅在通过设计器查看窗口时,才会在“属性”窗口中显示。 如果您在“源”视图中查看“属性”窗口,则会找到DeleteCommand
属性。
单击 DeleteQuery 属性中的省略号以显示命令和参数编辑器对话框(请参阅图 3)。 在此对话框中,可以指定 DELETE
SQL 语句并指定参数。 在命令文本框中输入以下查询 DELETE
(如果需要,请手动或使用查询生成器):
DELETE FROM Products
WHERE ProductID = @ProductID
接下来,单击“刷新参数”按钮,将 @ProductID
参数添加到以下参数列表中。
@ProductID 参数添加到 DELETE 命令参数列表中。 />
图 3:从“属性”窗口中选择 DeleteQuery 属性(单击以查看全尺寸图像)
不要为此参数提供值(将参数源保留为 None)。 向 GridView 添加删除支持后,GridView 将自动提供此参数值,并使用其 DataKeys
集合中对应于单击“删除”按钮的行的值。
注释
查询中使用的 DELETE
参数名称 必须与 GridView、DetailsView 或 FormView 中的值的名称 DataKeyNames
相同。 也就是说,DELETE
语句中的参数被有意命名为@ProductID
(而不是例如@ID
),因为 Products 表中的主键列名称(因此 GridView 中的 DataKeyNames 值)是ProductID
。
如果参数名称和 DataKeyNames
值不匹配,GridView 无法自动为参数分配集合中的 DataKeys
值。
在命令和参数编辑器对话框中输入与删除相关的信息后,单击“确定”,然后转到“源”视图检查生成的声明性标记:
<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 的智能标记现在包含“启用删除”选项。 请随意选择这个复选框。 如 插入、更新和删除概述中所述,这会导致 GridView 添加其 ShowDeleteButton
属性设置为 true
的 CommandField。 如图 4 所示,当通过浏览器访问页面时,将包含“删除”按钮。 通过删除某些产品来测试此页面。
图 4:每个 GridView 行现在都包含一个“删除”按钮(单击以查看全尺寸图像)
单击“删除”按钮时,发生回发,GridView 将为单击“删除”按钮的行分配 DataKeys
的 ProductID
集合值,并调用 SqlDataSource 的 Delete()
方法。 然后,SqlDataSource 控件连接到数据库并执行 DELETE
该语句。 然后,GridView 重新绑定到 SqlDataSource,返回并显示当前一组产品(不再包含刚刚删除的记录)。
注释
由于 GridView 使用其 DataKeys
集合填充 SqlDataSource 参数,因此 GridView 的属性必须设置为构成主键的 DataKeyNames
列,并且 SqlDataSource 返回 SelectCommand
这些列。 此外,SqlDataSource 中的 DeleteCommand
参数名称设置为 @ProductID
非常重要。 如果DataKeyNames
属性未设置或@ProductsID
参数未命名,单击“删除”按钮会导致回发,但实际上不会删除任何记录。
图 5 以图形方式描述此交互。 请参考 “检查与插入、更新和删除数据 Web 控件关联的事件链”教程,以获得与插入、更新和删除相关事件链的更详细讨论。
图 5:单击 GridView 中的“删除”按钮将调用 SqlDataSource s Delete()
方法
步骤 2:自动生成 INSERT、UPDATE 和 DELETE 语句
在检查步骤 1 时,INSERT
UPDATE
DELETE
可以通过“属性”窗口或控件的声明性语法来指定 SQL 语句。 但是,此方法要求我们手动写出 SQL 语句,这可以是单调且容易出错的。 幸运的是,“配置数据源”向导提供了一个选项,使您可以在使用“从视图中指定列”屏幕时自动生成INSERT
、UPDATE
和DELETE
语句。
让我们探索此自动生成选项。 将 DetailsView 添加到 InsertUpdateDelete.aspx
的设计器,并将其 ID
属性设置为 ManageProducts
。 接下来,从 DetailsView 的智能标记中选择创建一个新的数据源,并创建一个名为 ManageProductsDataSource
的 SqlDataSource。
图 6:创建新的 SqlDataSource 命名 ManageProductsDataSource
(单击以查看全尺寸图像)
在“配置数据源”向导中,选择使用 NORTHWINDConnectionString
连接字符串并单击“下一步”。 在“配置 Select 语句”屏幕中,保留所选表或视图单选按钮中的“指定列”,并从下拉列表中选择 Products
该表。 从复选框列表中选择 ProductID
、ProductName
、UnitPrice
和 Discontinued
列。
图 7:使用Products
表、返回ProductID
、ProductName
UnitPrice
列和Discontinued
列(单击以查看全尺寸图像)
要基于所选的表和列自动生成INSERT
、UPDATE
和DELETE
语句,请单击“高级”按钮,并勾选“一生成INSERT
、UPDATE
和DELETE
语句”的复选框。
图 8:选中“生成INSERT
”和UPDATE
DELETE
“语句”复选框
只有在所选表具有主键且主键列(或列)包含在返回的列列表中时,“生成INSERT
UPDATE
”和DELETE
“语句”复选框才可选中。 选中“生成INSERT
UPDATE
DELETE
语句”复选框后,“使用乐观并发”复选框将能够被选中,并将增强结果中的UPDATE
子句和DELETE
语句,以提供乐观并发控制。 目前,请暂时保留此复选框不选中;我们将在下一节教程中检查 SqlDataSource 控件的乐观并发性。
选中“生成INSERT
”和UPDATE
DELETE
“语句”复选框后,单击“确定”以返回到“配置选择语句”屏幕,然后单击“下一步”,然后单击“完成”完成“配置数据源向导。 完成向导后,Visual Studio 会将 BoundFields 添加到 DetailsView 中,用于ProductID
、ProductName
和UnitPrice
列,并为Discontinued
列添加一个 CheckBoxField。 在 DetailsView 智能标记中,选中“启用分页”选项,以便访问此页面的用户可以逐步浏览产品。 另请清除 DetailsView 的Width
和Height
属性。
请注意,智能标记具有“启用插入”、“启用编辑”和“启用删除”选项。 这是因为 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
中拥有每个Products列,其实只是包含了SelectCommand
中指定的那些列(不包括ProductID
列,因为它是不可编辑的IDENTITY
列,而且在插入时会自动赋值)。 此外,InsertCommand
、UpdateCommand
和 DeleteCommand
属性中的每个参数在 InsertParameters
、UpdateParameters
和 DeleteParameters
集合中都有相应的参数。
若要打开 DetailsView 的数据修改功能,请检查智能标记中的“启用插入”、“启用编辑”和“启用删除”选项。 这会添加一个 CommandField,并将其ShowInsertButton
、ShowEditButton
和ShowDeleteButton
属性设置为true
。
访问浏览器中的页面,并记下 DetailsView 中包含的“编辑”、“删除”和“新建”按钮。 单击“编辑”按钮可将 DetailsView 转换为编辑模式,其中显示属性 ReadOnly
设置为 false
TextBox(默认值)的每个 BoundField,并将 CheckBoxField 显示为复选框。
图 9:DetailsView 的默认编辑界面(单击以查看全尺寸图像)
同样,可以删除当前选定的产品或向系统添加新产品。 由于InsertCommand
语句仅与ProductName
、UnitPrice
和Discontinued
列一起使用,所以其他列在插入时自动分配有NULL
值或其数据库默认值。 与 ObjectDataSource 一样,如果 InsertCommand
缺少任何 NULL
不允许且没有默认值的数据库表列,则尝试执行 INSERT
语句时将发生 SQL 错误。
注释
DetailsView 的插入和编辑接口缺少任何类型的自定义或验证。 若要添加验证控件或自定义接口,需要将 BoundFields 转换为 TemplateFields。 有关详细信息,请参阅 向编辑和插入接口添加验证控件 以及 自定义数据修改接口 教程。
此外,请记住,为了更新和删除,DetailsView 使用当前产品的 DataKey
值,只有在配置 DataKeyNames
属性时才存在。 如果编辑或删除似乎不起作用,请确保设置属性 DataKeyNames
。
自动生成 SQL 语句的限制
由于“生成INSERT
”和UPDATE
DELETE
“语句”选项仅在从表中选取列时可用,因此对于更复杂的查询,你必须编写自己的INSERT
UPDATE
语句,就像DELETE
我们在步骤 1 中所做的那样。 通常,SQL SELECT
语句使用 JOIN
从一个或多个查找表中获取数据以便显示(例如在显示产品信息时,将 Categories
表的 CategoryName
字段带出)。 同时,我们可能希望允许用户编辑、更新或将数据插入核心表(Products
在本例中)。
INSERT
、UPDATE
和DELETE
语句可以手动输入,请考虑以下节省时间的提示。 最初设置 SqlDataSource,以便仅从 Products
表中拉取数据。 使用“配置数据源”向导的“指定表或视图”屏幕中的列,以便自动生成INSERT
和UPDATE
DELETE
语句。 然后,完成向导后,选择从“属性”窗口中配置 SelectQuery(或者,或者,返回到“配置数据源”向导,但使用“指定自定义 SQL 语句或存储过程”选项)。 然后更新 SELECT
语句以包含 JOIN
语法。 此方法提供自动生成的 SQL 语句的节省时间优势,并允许更自定义 SELECT
的语句。
自动生成INSERT
、UPDATE
和DELETE
语句的另一个限制是,INSERT
和UPDATE
语句中的列基于SELECT
语句返回的列。 但是,我们可能需要更新或插入更多或更少的字段。 例如,在步骤 2 中的示例中,也许我们希望 UnitPrice
BoundField 为只读。 在这种情况下,它不应出现在UpdateCommand
中。 或者,我们可能需要设置未显示在 GridView 中的表字段的值。 例如,添加新记录时,可能需要将 QuantityPerUnit
值设置为 TODO。
如果需要此类自定义,则需要通过“属性”窗口、向导中的“指定自定义 SQL 语句”或存储过程选项或声明性语法手动进行自定义。
注释
添加数据 Web 控件中没有相应字段的参数时,请记住,这些参数值需要以某种方式分配值。 这些值可以是:直接在InsertCommand
UpdateCommand
或中硬编码;可能来自某些预定义的源(页面上的查询字符串、会话状态、Web 控件等);也可以按编程方式分配,如前面的教程所示。
概要
为了使数据 Web 控件利用其内置插入、编辑和删除功能,它们绑定到的数据源控件必须提供此类功能。 对于 SqlDataSource,这意味着必须将INSERT
、UPDATE
和DELETE
SQL 语句分配给InsertCommand
、UpdateCommand
和DeleteCommand
属性。 可以通过“配置数据源”向导手动添加这些属性和相应的参数集合或自动生成这些属性。 在本教程中,我们研究了这两种技术。
我们在 实现乐观并发 教程中研究了如何使用 ObjectDataSource 实现乐观并发。 SqlDataSource 控件还提供乐观并发支持。 如步骤 2 中所述,在自动生成INSERT
、UPDATE
和DELETE
语句时,向导提供了“使用乐观并发”选项。 在下一个教程中,我们将看到,在 SqlDataSource 中使用乐观并发会修改 WHERE
语句中的 UPDATE
和 DELETE
子句,以确保其他列的值自上次在页面上显示以来没有发生更改。
快乐编程!
关于作者
斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 《Sams Teach Yourself ASP.NET 2.0 in 24 Hours》。 可以通过 mitchell@4GuysFromRolla.com 联系到他。