Inserting, Updating, and Deleting Data with the SqlDataSource (C#)

by Scott Mitchell

Download PDF

In previous tutorials we learned how the ObjectDataSource control allowed for inserting, updating, and deleting of data. The SqlDataSource control supports the same operations, but the approach is different, and this tutorial shows how to configure the SqlDataSource to insert, update, and delete data.

Introduction

As discussed in An Overview of Inserting, Updating, and Deleting, the GridView control provides built-in updating and deleting capabilities, while the DetailsView and FormView controls include inserting support along with editing and deleting functionality. These data modification capabilities can be plugged directly into a data source control without a line of code needing to be written. An Overview of Inserting, Updating, and Deleting examined using the ObjectDataSource to facilitate inserting, updating, and deleting with the GridView, DetailsView, and FormView controls. Alternatively, the SqlDataSource can be used in place of the ObjectDataSource.

Recall that to support inserting, updating, and deleting, with the ObjectDataSource we needed to specify the object layer methods to invoke to perform the insert, update, or delete action. With the SqlDataSource, we need to provide INSERT, UPDATE, and DELETE SQL statements (or stored procedures) to execute. As we'll see in this tutorial, these statements can be created manually or can be automatically generated by the SqlDataSource s Configure Data Source wizard.

Note

Since we ve already discussed the inserting, editing, and deleting capabilities of the GridView, DetailsView, and FormView controls, this tutorial will focus on configuring the SqlDataSource control to support these operations. If you need to brush up on implementing these features within the GridView, DetailsView, and FormView, return to the Editing, Inserting, and Deleting Data tutorials, starting with An Overview of Inserting, Updating, and Deleting.

Step 1: Specifying INSERT, UPDATE, and DELETE Statements

As we ve seen in the past two tutorials, to retrieve data from a SqlDataSource control we need to set two properties:

  1. ConnectionString, which specifies what database to send the query to, and
  2. SelectCommand, which specifies the ad-hoc SQL statement or stored procedure name to execute to return the results.

For SelectCommand values with parameters, the parameter values are specified via the SqlDataSource s SelectParameters collection and can include hard-coded values, common parameter source values (querystring fields, session variables, Web control values, and so on), or can be programmatically assigned. When the SqlDataSource control s Select() method is invoked either programmatically or automatically from a data Web control a connection to the database is established, the parameter values are assigned to the query, and the command is shuttled off to the database. The results are then returned as either a DataSet or DataReader, depending on the value of the control s DataSourceMode property.

Along with selecting data, the SqlDataSource control can be used to insert, update, and delete data by supplying INSERT, UPDATE, and DELETE SQL statements in much the same way. Simply assign the InsertCommand, UpdateCommand, and DeleteCommand properties the INSERT, UPDATE, and DELETE SQL statements to execute. If the statements have parameters (as they most always will), include them in the InsertParameters, UpdateParameters, and DeleteParameters collections.

Once an InsertCommand, UpdateCommand, or DeleteCommand value has been specified, the Enable Inserting, Enable Editing, or Enable Deleting option in the corresponding data Web control s smart tag will become available. To illustrate this, let s take an example from the Querying.aspx page we created in the Querying Data with the SqlDataSource Control tutorial and augment it to include delete capabilities.

Start by opening the InsertUpdateDelete.aspx and Querying.aspx pages from the SqlDataSource folder. From the Designer on the Querying.aspx page, select the SqlDataSource and GridView from the first example (the ProductsDataSource and GridView1 controls). After selecting the two controls, go to the Edit menu and choose Copy (or just hit Ctrl+C). Next, go to the Designer of InsertUpdateDelete.aspx and paste in the controls. After you have moved the two controls over to InsertUpdateDelete.aspx, test out the page in a browser. You should see the values of the ProductID, ProductName, and UnitPrice columns for all of the records in the Products database table.

All of the Products are Listed, Ordered by ProductID

Figure 1: All of the Products are Listed, Ordered by ProductID (Click to view full-size image)

Adding the SqlDataSource's DeleteCommand and DeleteParameters Properties

At this point we have a SqlDataSource that simply returns all of the records from the Products table and a GridView that renders this data. Our goal is to extend this example to allow for the user to delete products via the GridView. To accomplish this we need to specify values for the SqlDataSource control s DeleteCommand and DeleteParameters properties and then configure the GridView to support deleting.

The DeleteCommand and DeleteParameters properties can be specified in a number of ways:

  • Through the declarative syntax
  • From the Properties window in the Designer
  • From the Specify a custom SQL statement or stored procedure screen in the Configure Data Source wizard
  • Via the Advanced button in the Specify columns from a table of view screen in the Configure Data Source wizard, which will actually automatically generate the DELETE SQL statement and parameter collection used in the DeleteCommand and DeleteParameters properties

We'll examine how to automatically have the DELETE statement created in Step 2. For now, let s use the Properties window in the Designer, although the Configure Data Source wizard or declarative syntax option would work just as well.

From the Designer in InsertUpdateDelete.aspx, click on the ProductsDataSource SqlDataSource and then bring up the Properties window (from the View menu, choose Properties window, or simply hit F4). Select the DeleteQuery property, which will bring up a set of ellipses.

Screenshot showing the ProductsDataSource Properties window with the DeleteQuery property selected.

Figure 2: Select the DeleteQuery Property from the Properties Window

Note

The SqlDataSource doesn t have a DeleteQuery property. Rather, DeleteQuery is a combination of the DeleteCommand and DeleteParameters properties and is only listed in the Properties window when viewing the window through the Designer. If you are looking at the Properties window in the Source view, you'll find the DeleteCommand property instead.

Click the ellipses in the DeleteQuery property to bring up the Command and Parameter Editor dialog box (see Figure 3). From this dialog box you can specify the DELETE SQL statement and specify the parameters. Enter the following query into the DELETE command textbox (either manually or using the Query Builder, if you prefer):

DELETE FROM Products
WHERE ProductID = @ProductID

Next, click the Refresh Parameters button to add the @ProductID parameter to the list of parameters below.

Screenshot showing the Command and Parameter Editor window with the <span class=@ProductID parameter added to the list of DELETE command parameters." />

Figure 3: Select the DeleteQuery Property from the Properties Window (Click to view full-size image)

Do not provide a value for this parameter (leave its Parameter source at None ). Once we add deleting support to the GridView, the GridView will automatically supply this parameter value, using the value of its DataKeys collection for the row whose Delete button was clicked.

Note

The parameter name used in the DELETE query must be the same as the name of the DataKeyNames value in the GridView, DetailsView, or FormView. That is, the parameter in the DELETE statement is purposefully named @ProductID (instead of, say, @ID), because the primary key column name in the Products table (and therefore the DataKeyNames value in the GridView) is ProductID.

If the parameter name and DataKeyNames value doesn t match, the GridView cannot automatically assign the parameter the value from the DataKeys collection.

After entering the delete-related information into the Command and Parameter Editor dialog box click OK and go to the Source view to examine the resulting declarative markup:

<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>

Note the addition of the DeleteCommand property as well as the <DeleteParameters> section and the Parameter object named productID.

Configuring the GridView for Deleting

With the DeleteCommand property added, the GridView s smart tag now contains the Enable Deleting option. Go ahead and check this checkbox. As discussed in An Overview of Inserting, Updating, and Deleting, this causes the GridView to add a CommandField with its ShowDeleteButton property set to true. As Figure 4 shows, when the page is visited through a browser a Delete button is included. Test this page out by deleting some products.

Each GridView Row Now Includes a Delete Button

Figure 4: Each GridView Row Now Includes a Delete Button (Click to view full-size image)

Upon clicking a Delete button, a postback occurs, the GridView assigns the ProductID parameter the value of the DataKeys collection value for the row whose Delete button was clicked, and invokes the SqlDataSource s Delete() method. The SqlDataSource control then connects to the database and executes the DELETE statement. The GridView then rebinds to the SqlDataSource, getting back and displaying the current set of products (which no longer includes the just-deleted record).

Note

Since the GridView uses its DataKeys collection to populate the SqlDataSource parameters, it s vital that the GridView s DataKeyNames property be set to the column(s) that constitute the primary key and that the SqlDataSource s SelectCommand returns these columns. Moreover, it s important that the parameter name in the SqlDataSource s DeleteCommand is set to @ProductID. If the DataKeyNames property is not set or the parameter is not named @ProductsID, clicking the Delete button will cause a postback, but won't actually delete any record.

Figure 5 depicts this interaction graphically. Refer back to the Examining the Events Associated with Inserting, Updating, and Deleting tutorial for a more detailed discussion on the chain of events associated with inserting, updating, and deleting from a data Web control.

Clicking the Delete Button in the GridView Invokes the SqlDataSource s Delete() Method

Figure 5: Clicking the Delete Button in the GridView Invokes the SqlDataSource s Delete() Method

Step 2: Automatically Generating the INSERT, UPDATE, and DELETE Statements

As Step 1 examined, INSERT, UPDATE, and DELETE SQL statements can be specified through the Properties window or the control s declarative syntax. However, this approach requires that we manually write out the SQL statements by hand, which can be monotonous and error-prone. Fortunately, the Configure Data Source wizard provides an option to have the INSERT, UPDATE, and DELETE statements automatically generated when using the Specify columns from a table of view screen.

Let's explore this automatic generation option. Add a DetailsView to the Designer in InsertUpdateDelete.aspx and set its ID property to ManageProducts. Next, from the DetailsView s smart tag, choose to create a new data source and create a SqlDataSource named ManageProductsDataSource.

Create a New SqlDataSource Named ManageProductsDataSource

Figure 6: Create a New SqlDataSource Named ManageProductsDataSource (Click to view full-size image)

From the Configure Data Source wizard, opt to use the NORTHWINDConnectionString connection string and click Next. From the Configure the Select Statement screen, leave the Specify columns from a table or view radio button selected and pick the Products table from the drop-down list. Select the ProductID, ProductName, UnitPrice, and Discontinued columns from the checkbox list.

Using the Products Table, Return the ProductID, ProductName, UnitPrice, and Discontinued Columns

Figure 7: Using the Products Table, Return the ProductID, ProductName, UnitPrice, and Discontinued Columns (Click to view full-size image)

To automatically generate INSERT, UPDATE, and DELETE statements based on the selected table and columns, click the Advanced button and check the Generate INSERT, UPDATE, and DELETE statements checkbox.

Check the Generate INSERT, UPDATE, and DELETE statements Checkbox

Figure 8: Check the Generate INSERT, UPDATE, and DELETE statements Checkbox

The Generate INSERT, UPDATE, and DELETE statements checkbox will only be checkable if the table selected has a primary key and the primary key column (or columns) are included in the list of returned columns. The Use optimistic concurrency checkbox, which becomes selectable once the Generate INSERT, UPDATE, and DELETE statements checkbox has been checked, will augment the WHERE clauses in the resulting UPDATE and DELETE statements to provide optimistic concurrency control. For now, leave this checkbox unchecked; we'll examine optimistic concurrency with the SqlDataSource control in the next tutorial.

After checking the Generate INSERT, UPDATE, and DELETE statements checkbox, click OK to return to the Configure Select Statement screen, then click Next, and then Finish, to complete the Configure Data Source wizard. Upon completing the wizard, Visual Studio will add BoundFields to the DetailsView for the ProductID, ProductName, and UnitPrice columns and a CheckBoxField for the Discontinued column. From the DetailsView s smart tag, check the Enable Paging option so that the user visiting this page can step through the products. Also clear out the DetailsView s Width and Height properties.

Notice that the smart tag has the Enable Inserting, Enable Editing, and Enable Deleting options available. This is because the SqlDataSource contains values for its InsertCommand, UpdateCommand, and DeleteCommand, as the following declarative syntax shows:

<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>

Note how the SqlDataSource control has had values automatically set for its InsertCommand, UpdateCommand, and DeleteCommand properties. The set of columns referenced in the InsertCommand and UpdateCommand properties are based on those in the SELECT statement. That is, rather than having every Products column in the InsertCommand and UpdateCommand, there are only those columns specified in the SelectCommand (less ProductID, which is omitted because it s an IDENTITY column, whose value cannot be changed when edited and which is automatically assigned when inserting). Moreover, for each parameter in the InsertCommand, UpdateCommand, and DeleteCommand properties there are corresponding parameters in the InsertParameters, UpdateParameters, and DeleteParameters collections.

To turn on the DetailsView s data modification features, check the Enable Inserting, Enable Editing, and Enable Deleting options in its smart tag. This adds a CommandField with its ShowInsertButton, ShowEditButton, and ShowDeleteButton properties set to true.

Visit the page in a browser and note the Edit, Delete, and New buttons included in the DetailsView. Clicking the Edit button turns the DetailsView into edit mode, which displays each BoundField whose ReadOnly property is set to false (the default) as a TextBox, and the CheckBoxField as a checkbox.

The DetailsView s Default Editing Interface

Figure 9: The DetailsView s Default Editing Interface (Click to view full-size image)

Similarly, you can delete the currently selected product or add a new product to the system. Since the InsertCommand statement only works with the ProductName, UnitPrice, and Discontinued columns, the other columns have either NULL or their default value assigned by the database upon insert. Just like with the ObjectDataSource, if the InsertCommand is missing any database table columns that don t allow NULL s and don t have a default value, a SQL error will occur when attempting to execute the INSERT statement.

Note

The DetailsView s inserting and editing interfaces lack any sort of customization or validation. To add validation controls or to customize the interfaces, you need to convert the BoundFields to TemplateFields. Refer to the Adding Validation Controls to the Editing and Inserting Interfaces and Customizing the Data Modification Interface tutorials for more information.

Also, keep in mind that for updating and deleting, the DetailsView uses the current product s DataKey value, which is only present if the DataKeyNames property is configured. If editing or deleting appears to have no effect, ensure that the DataKeyNames property is set.

Limitations of Automatically Generating SQL Statements

Since the Generate INSERT, UPDATE, and DELETE statements option is only available when picking columns from a table, for more complex queries you will have to write your own INSERT, UPDATE, and DELETE statements like we did in Step 1. Commonly, SQL SELECT statements use JOIN s to bring back data from one or more lookup tables for display purposes (such as bringing back the Categories table s CategoryName field when displaying product information). At the same time, we might want to allow the user to edit, update, or insert data into the core table (Products, in this case).

While the INSERT, UPDATE, and DELETE statements can be entered manually, consider the following time-saving tip. Initially setup the SqlDataSource so that it pulls back data just from the Products table. Use the Configure Data Source wizard s Specify columns from a table or view screen so that you can automatically generate the INSERT, UPDATE, and DELETE statements. Then, after completing the wizard, choose to configure the SelectQuery from the Properties window (or, alternatively, go back to the Configure Data Source wizard, but use the Specify a custom SQL statement or stored procedure option). Then update the SELECT statement to include the JOIN syntax. This technique offers the time-saving benefits of the automatically generated SQL statements and allows for a more customized SELECT statement.

Another limitation of automatically generating the INSERT, UPDATE, and DELETE statements is that the columns in the INSERT and UPDATE statements are based on the columns returned by the SELECT statement. We may need to update or insert more or fewer fields, however. For example, in the example from Step 2, maybe we want to have the UnitPrice BoundField be read-only. In that case, it shouldn't appear in the UpdateCommand. Or we may want to set the value of a table field that does not appear in the GridView. For example, when adding a new record we may want the QuantityPerUnit value set to TODO .

If such customizations are required, you need to make them manually, either through the Properties window, the Specify a custom SQL statement or stored procedure option in the wizard, or via the declarative syntax.

Note

When adding parameters that do not have corresponding fields in the data Web control, keep in mind that these parameters values will need to be assigned values in some manner. These values can be: hard-coded directly in the InsertCommand or UpdateCommand; can come from some pre-defined source (the querystring, session state, Web controls on the page, and so on); or can be assigned programmatically, as we saw in the preceding tutorial.

Summary

In order for the data Web controls to utilize their built-in inserting, editing, and deleting capabilities, the data source control they are bound to must offer such functionality. For the SqlDataSource, this means that INSERT, UPDATE, and DELETE SQL statements must be assigned to the InsertCommand, UpdateCommand, and DeleteCommand properties. These properties, and the corresponding parameters collections, can be added manually or generated automatically through the Configure Data Source wizard. In this tutorial we examined both techniques.

We examined using optimistic concurrency with the ObjectDataSource in the Implementing Optimistic Concurrency tutorial. The SqlDataSource control also provides optimistic concurrency support. As noted in Step 2, when automatically generating the INSERT, UPDATE, and DELETE statements, the wizard offers a Use optimistic concurrency option. As we'll see in the next tutorial, using optimistic concurrency with the SqlDataSource modifies the WHERE clauses in the UPDATE and DELETE statements to ensure that the values for the other columns haven't changed since the data was last displayed on the page.

Happy Programming!

About the Author

Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, trainer, and writer. His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. He can be reached at mitchell@4GuysFromRolla.com. or via his blog, which can be found at http://ScottOnWriting.NET.