图8:选中“生成INSERT、UPDATE和DELETE命令”选项
当查询返回的那些列包含主键列(有时几个列都是主键列)时,才能启用“生成INSERT、UPDATE和DELETE命令”选项。当选择了“生成INSERT、UPDATE和DELETE命令”选项后,才能选择“使用开放式并发”选项。当选择该选项后,就将在UPDATE和DELETE命令里增加WHERE字句,以提供开放式并发控制。现在先不忙选择“使用开放式并发”选项,我们将在后面的教程里讨论如何使SqlDataSource控件实现开放式并发。
当选择“生成INSERT、UPDATE和DELETE命令”选项后,点“OK”回到“设置选择命令”界面,再点下一步,点完成。完成向导后,Visual Studio将会为DetailsView控件增加ProductID, ProductName和UnitPrice三个绑定列(BoundFields),和一个Discontinued单选框列(CheckBoxField )。在DetailsView控件的智能标签里选择分页项,并清空DetailsView的宽、高属性。
我们注意到智能标签里还包括插入、编辑、删除选项可用,这是因为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>
注意:SqlDataSourc控件是如何自动的为InsertCommand,UpdateCommand和DeleteCommand属性赋值的。InsertCommand和UpdateCommand属性里涉及到的列取决于SELECT命令里的列,换句话说,并不是表Products的所有列都出现在InsertCommand和UpdateCommand属性里。在InsertCommand和UpdateCommand属性里只能使用SelectCommand返回的那些列(列ProductID除外,因为它是一个IDENTITY列,IDENTITY列的值在编辑的时候不允许改变,而且新插入一条记录时,自动对IDENTITY列赋值)。另外在InsertCommand, UpdateCommand和 DeleteCommand属性里出现的每个参数,在<DeleteParameters>、<UpdateParameters>、<InsertParameters>标记里都有对应的参数。
再转向DetailsView的数据修改属性,在智能标签里启用插入、编辑、删除功能。这样会添加一个CommandField,并将ShowInsertButton、ShowEditButton和 ShowDeleteButton属性设置为true。
在浏览器访问该页,注意到编辑、删除、新建按钮出现在DetailsView控件中,点“编辑”按钮,DetailsView控件将进入编辑模式,那些ReadOnly属性设置为false(默认)的绑定列将变成一个文本框,而CheckBoxField将变成单选框。
图9:DetailsView控件的默认编辑界面
类似的,你可以将当前选定行删除,或向系统增加新产品记录。由于InsertCommand语句里只包含ProductName, UnitPrice和Discontinued三列,当完成新增记录时,其它列要么为NULL要么使用数据库默认值。和ObjectDataSource控件一样,假设数据库表中存在这样的列,其值不允许为NULL,且未设置默认值,如果在
InsertCommand命令里未包含该列的话,当你试图执行该INSERT语句的时候将出错。
注意:DetailsView控件的默认插入和编辑界面不能实现用户定制和确认功能,为了能实现用户定制及添加确认控件,我们需要将绑定列(BoundFields)转换成模板列(TemplateFields)。获得更多这方面的信息,请参阅前面的教程Adding Validation Controls to the Editing以及Customizing the Data Modification Interface 。同时谨记,当进行更新和删除操作时,DetailsView控件将使用当前产品的DataKey值。如果编辑或删除失败话,检查DataKeyNames属性是否设置正确。
自动生成SQL语句的局限性
只有当选择从表返回列时,才能选用“自动生成INSERT, UPDATE和DELETE命令”选项,从而自动生成SQL语句。然而,对更复杂的查询来说,我们将像第一步那样手动书写INSERT, UPDATE和DELETE语句。 一般来说,我们在SQL SELECT命令里使用JOINs将不同表的不同表的数据连接起来(打个比方,我们在显示产品信息的同时希望显示供应商名字CategoryName,但是Products表里没有CategoryName列,那就只有调动表Categories的CategoryName列)。同时我们对“主”表执行编辑、更新和删除操作(具体到本例,“主”表就是Products表)
对这种需要手工输入的比较复杂的查询,按以下步骤来做可以省时一些。首先,创建一个从表Products返回数据的SqlDataSource控件,在其“设置数据源向导”里选择“指定来自表或视图的列”模式来自动地生成INSERT, UPDATE和DELETE语句。完成设置后在属性窗口打开SelectQuery属性(或者直接在“设置数据源向导”里选用“自定义SQL语句或存储过程”模式),最后在SELECT命令里添加JOIN字句。这个方法既有自动生成SQL语句省时的优点,又可以自定义SELECT语句。
另一个局限性在于,自动生成的INSERT和UPDAT命令里包含的是那些SELECT命令返回的列,而我们实际需要插入或更新的列可能比这些列多也可能比这些列少。比如在第2步中,如果我们要将UnitPrice设置为只读,那么它就不应该UpdateCommand语句里面, 或者我们希望在新增记录时对QuantityPerUnit赋值为“TODO”,但在GridView控件里并没有显示QuantityPerUnit列。
对这种情况,我们需要手工输入代码。要么直接声明代码,要么在“设置数据源向导”里选择“指定SQL语句或存储过程”模式,要么通过属性窗口设置。
注意:当新增一个参数时,如果在数据Web控件里没有与该参数对应的列话,我们应通过其他方法对该参数赋值:在InsertCommand和UpdateCommand语句里通过硬编码赋值;通过预定义源(比如查询字符串、session状态,页面上的控件等)传递参数;通过编程对参数赋值。
总结:
要使数据Web控件能启用其内建的插入、编辑、删除功能,它绑定的数据源控件首先要提供这些功能函数。对SqlDataSource来说,就是其InsertCommand, UpdateCommand和DeleteCommand属性必须包含INSERT,UPDATE和DELETE语句。在本节教程我们探讨了手工和自动2种生成代码的方法。
祝编程快乐!
作者简介
本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。
更多SQL内容来自木庄网络博客