Getting Started
  Introduction
  What is ASP.NET?
  Language Support

ASP.NET Web Forms
  Introducing Web Forms
  Working with Server Controls
  Applying Styles to Controls
  Server Control Form Validation
  Web Forms User Controls
  Data Binding Server Controls
  Server-Side Data Access
  Data Access and Customization
  Working with Business Objects
  Authoring Custom Controls
  Web Forms Controls Reference
  Web Forms Syntax Reference

ASP.NET Web Services
  Introducing Web Services
  Writing a Simple Web Service
  Web Service Type Marshalling
  Using Data in Web Services
  Using Objects and Intrinsics
  The WebService Behavior
  HTML Pattern Matching

ASP.NET Web Applications
  Application Overview
  Using the Global.asax File
  Managing Application State
  HttpHandlers and Factories

Cache Services
  Caching Overview
  Page Output Caching
  Page Fragment Caching
  Page Data Caching

Configuration
  Configuration Overview
  Configuration File Format
  Retrieving Configuration

Deployment
  Deploying Applications
  Using the Process Model
  Handling Errors

Security
  Security Overview
  Authentication & Authorization
  Windows-based Authentication
  Forms-based Authentication
  Authorizing Users and Roles
  User Account Impersonation
  Security and WebServices

Localization
  Internationalization Overview
  Setting Culture and Encoding
  Localizing ASP.NET Applications
  Working with Resource Files

Tracing
  Tracing Overview
  Trace Logging to Page Output
  Application-level Trace Logging

Debugging
  The SDK Debugger

Performance
  Performance Overview
  Performance Tuning Tips
  Measuring Performance

ASP to ASP.NET Migration
  Migration Overview
  Syntax and Semantics
  Language Compatibility
  COM Interoperability
  Transactions

Sample Applications
  A Personalized Portal
  An E-Commerce Storefront
  A Class Browser Application
  IBuySpy.com

  Get URL for this page

Server-Side Data Access


Introduction to Server-Side Data

Data access is the heart of any real-world application, and ASP.NET provides a rich set of controls that are well-integrated with the managed data access APIs provided in the common language runtime. This section walks through several iterations of a sample that uses the ASP.NET DataGrid control to bind to the results of SQL queries and XML data files. This section assumes some familiarity with database fundamentals and the SQL query language.

Server-side data access is unique in that Web pages are basically stateless, which presents some difficult challenges when trying to perform transactions such as inserting or updating records from a set of data retrieved from a database. As you'll see in this section, the DataGrid control can help manage these challenges, allowing you to concentrate more on your application logic and less on the details of state management and event handling.



Connections, Commands, and Datasets

The common language runtime provides a complete set of managed data access APIs for data-intensive application development. These APIs help to abstract the data and present it in a consistent way regardless of its actual source (SQL Server, OLEDB, XML, and so on). There are essentially three objects you will work with most often: connections, commands, and datasets.

  • A connection represents a physical connection to some data store, such as SQL Server or an XML file.
  • A command represents a directive to retrieve from (select) or manipulate (insert, update, delete) the data store.
  • A dataset represents the actual data an application works with. Note that datasets are always disconnected from their source connection and data model and can be modified independently. However, changes to a dataset can be easily reconciled with the originating data model.

For a more detailed walkthrough of the managed data access solution in the common language runtime, please read the ADO.NET Overview section of this tutorial.

Accessing SQL-based Data

An application typically needs to perform one or more select, insert, update, or delete queries to a SQL database. The following table shows an example of each of these queries.

Query Example
Simple Select SELECT * from Employees WHERE FirstName = 'Bradley';
Join Select SELECT * from Employees E, Managers M WHERE E.FirstName = M.FirstName;
Insert INSERT into Employees VALUES ('123-45-6789','Bradley','Millington','Program Manager');
Update UPDATE Employees SET Title = 'Development Lead' WHERE FirstName = 'Bradley';
Delete DELETE from Employees WHERE Productivity < 10;

To give your page access to the classes you will need to perform SQL data access, you must import the System.Data and System.Data.SqlClient namespaces into your page.

To perform a select query to a SQL database, you create a SqlConnection to the database passing the connection string, and then construct a SqlDataAdapter object that contains your query statement. To populate a DataSet object with the results from the query, you call the command's Fill method.


Dim myConnection As New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes")
Dim myCommand As New SqlDataAdapter("select * from Authors", myConnection)

Dim ds As New DataSet()
myCommand.Fill(ds, "Authors")
VB

As mentioned earlier in this section, the benefit of using a dataset is that it gives you a disconnected view of the database. You can operate on a dataset in your application, and then reconcile your changes with the actual database later. For long-running applications this is often the best approach. For Web applications, you are usually performing short operations with each request (commonly to simply display the data). You often don't need to hold a DataSet object over a series of several requests. For situations like these, you can use a SqlDataReader.

A SqlDataReader provides a forward-only, read-only pointer over data retrieved from a SQL database. To use a SqlDataReader, you declare a SqlCommand instead of a SqlDataAdapter. The SqlCommand exposes an ExecuteReader method that returns a SqlDataReader. Note also that you must explicitly open and close the SqlConnection when you use a SqlCommand. After a call to ExecuteReader, the SqlDataReader can be bound to an ASP.NET server control, as you'll see in the next section.


Dim myConnection As SqlConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes")
Dim myCommand As SqlCommand = New SqlCommand("select * from Authors", myConnection)

myConnection.Open()


Dim dr As SqlDataReader = myCommand.ExecuteReader()

...

myConnection.Close()
VB

When performing commands that do not require data to be returned, such as inserts, updates, and deletes, you also use a SqlCommand. The command is issued by calling an ExecuteNonQuery method, which returns the number of rows affected. Note that the connection must be explicitly opened when you use the SqlCommand; the SqlDataAdapter automatically handles opening the connection for you.


Dim myConnection As New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes")
Dim myCommand As New SqlCommand( _
                   "UPDATE Authors SET phone='(800) 555-5555' WHERE au_id = '123-45-6789'",  _
                    myConnection)

myCommand.Connection.Open()
myCommand.ExecuteNonQuery()
myCommand.Connection.Close()
VB

Important: Always remember to close the connection to the data model before the page finishes executing. If you do not close the connection, you might inadvertently exhaust the connection limit while waiting for the page instances to be handled by garbage collection.

Binding SQL Data to a DataGrid

The following sample shows a simple select query bound to a DataGrid control. The DataGrid renders a table containing the SQL data.

 
VB DataGrid1.aspx

[Run Sample] | [View Source]

Like the DropDownList shown in the Data Binding section, the DataGrid control supports a DataSource property that takes an IEnumerable or ICollection, as well as a DataSet. You can use a DataSet by assigning the DefaultView property of a table contained in the DataSet to the name of the table you wish to use within the DataSet. The DefaultView property represents the current state of a table within a DataSet, including any changes which have been made by application code (row deletions or value changes, for example). After setting the DataSource property, you call DataBind() to populate the control.

VB

An alternative syntax is to specify both a DataSource and a DataMember. In this case, ASP.NET automatically gets the DefaultView for you.


MyDataGrid.DataSource=ds
MyDataGrid.DataMember="Authors"
MyDataGrid.DataBind()
VB

You can also bind directly to a SqlDataReader. In this case you are only displaying data, so the forward-only nature of the SqlDataReader is perfectly suited to this scenario, and you benefit from the performance boost that SqlDataReader provides.

 
VB DataGrid1.1.aspx

[Run Sample] | [View Source]

Note: For the remainder of this section, only the DataSet model of data access is shown; however, any of these samples could be re-written to take advantage of SQLDataReader as well.

Performing a Parameterized Select

You can also perform a parameterized select using the SqlDataAdapter object. The following sample shows how you can modify the data selected using the value posted from a select HtmlControl.

 
VB DataGrid2.aspx

[Run Sample] | [View Source]

The SqlDataAdapter maintains a Parameters collection that can be used to replace variable identifiers (denoted by an "@" in front of the name) with values. You add a new SqlParameter to this collection that specifies the name, type, and size of the parameter, and then set its Value property to the value of the select.

VB

Important: Note that the DataGrid's EnableViewState property has been set to false. If the data will be populated in each request, there is no benefit to having the DataGrid store state information to be sent through a round trip with form posts. Because the DataGrid stores all of its data when maintaining state, it is important to turn it off when appropriate to improve the performance of your pages.

DataGrid2.aspx statically populates the values of the select box, but this will not work well if those values ever change in the database. Because the select HtmlControl also supports an IEnumerable DataSource property, you can use a select query to dynamically populate the select box instead, which guarantees that the database and user interface are always in sync. The following sample demonstrates this process.

 
VB DataGrid3.aspx

[Run Sample] | [View Source]


Inserting Data in a SQL Database

To insert a row into the database, you can add a simple input form to the page, and execute an insert command in the form submit event handler. Just as in the previous two samples, you use the command object's Parameters collection to populate the command's values. Note that you also check to make sure the required values are not null before attempting to insert into the database. This prevents an accidental violation of the database's field constraints. You also execute the insert command inside of a try/catch block, just in case the primary key for inserted row already exists.

 
VB DataGrid4.aspx

[Run Sample] | [View Source]

Instead of explicitly checking the input values, you could have just as easily used the validator controls provided with ASP.NET. The following sample shows how to do that. Note that using the RegEx Validator provides the additional benefit of checking the format for the author ID, zip code, and phone number fields.

 
VB DataGrid5.aspx

[Run Sample] | [View Source]


Updating Data in a SQL Database

Updating a database can often be tricky in Web applications. The DataGrid control provides some built-in support for this scenario that makes updates easier. To allow rows to be edited, the DataGrid supports an integer EditItemIndex property, which indicates which row of the grid should be editable. When this property is set, the DataGrid renders the row at that index as text input boxes instead of simple labels. A value of -1 (the default) indicates that no rows are editable. The page can enclose the DataGrid in a server-side form and get access to the edited data through the DataGrid's object model.

To figure out which row should be editable, you need a way to accept some input from the user about which row they would like to edit. The DataGrid can contain an EditCommandColumn that renders links for firing three special events: EditCommand, UpdateCommand, and CancelCommand. The EditCommandColumn is declaratively added to the DataGrid's Columns collection, as shown in the following example.

On the DataGrid tag itself, you wire event handlers to each of the commands fired from the EditCommandColumn. The DataGridCommandEventArgs argument of these handlers gives you direct access to the index selected by the client, which you use to set the DataGrid's EditItemIndex. Note that you need to re-bind the DataGrid for the change to take effect, as shown in the following example.


Public Sub MyDataGrid_Edit(sender As Object, E As DataGridCommandEventArgs)
    MyDataGrid.EditItemIndex = E.Item.ItemIndex
    BindGrid()
End Sub
VB

When a row of the DataGrid is being edited, the EditCommandColumn renders the Update and Cancel links. If the client selects Cancel, you simply set the EditItemIndex back to -1. If the client selects Update, however, you need to execute your update command to the database. Performing an update query requires that you know the primary key in the database for the row you wish to update. To support this, the DataGrid exposes a DataKeyField property that you can set to the field name for the primary key. In the event handler wired to the UpdateCommand, you can retrieve the key name from the DataGrid's DataKeys collection. You index into this collection using the ItemIndex of the event, as shown in the following example.


myCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CType(E.Item.ItemIndex, Integer))
VB

At the end of the Update event handler, you set the EditItemIndex back to -1. The following sample demonstrates this code in action.

 
VB DataGrid6.aspx

[Run Sample] | [View Source]

One problem with the preceding example is that the primary key field (au_id) also renders as a text input box when a row is editable. You don't want the client to change this value, because you need it to determine which row to update in the database. Fortunately, you can disable this column from rendering as a text box by specifying exactly what each column looks like for the editable row. You do this by defining each row in the DataGrid's Columns collection, using the BoundColumn control to assign data fields with each column. Using this technique gives you complete control over the order of the columns, as well as their ReadOnly properties. For the au_id column you set the ReadOnly property to true. When a row is in edit mode, this column will continue to render as a Label. The following sample demonstrates this technique.

 
VB DataGrid7.aspx

[Run Sample] | [View Source]

BoundColumn controls aren't the only controls you can set in the DataGrid's Columns collection. You can also specify a TemplateColumn, which gives you complete control over the contents of the column. The template is just arbitrary content; you can render anything you like, including server controls, inside the DataGrid's columns. The following sample demonstrates using the TemplateColumn control to render the "State" column as a drop-down list and the "Contract" column as a check box HtmlControl. The ASP.NET data binding syntax is used to output the data field value within the template. Note that there is a bit of tricky logic to make the drop-down list and check box reflect the state of the data inside the row.

 
VB DataGrid8.aspx

[Run Sample] | [View Source]

Just as you can place a drop-down list or check box HtmlControl in a TemplateColumn, you can also place other controls there. The following sample adds Validator controls to the columns to check the client input before attempting to perform the update.

 
VB DataGrid9.aspx

[Run Sample] | [View Source]


Deleting Data in a SQL Database

Deleting from a database is very similar to an update or insert command, but you still need a way to determine the particular row of the grid to delete. Another control that can be added to the DataGrid's Columns collection is the ButtonColumn control, which simply renders a button control. ButtonColumn supports a CommandName property that can be set to Delete. On the DataGrid, you wire an event handler to the DeleteCommand, where you perform the delete operation. Again, you use the DataKeys collection to determine the row selected by the client. The following sample demonstrates this process.

 
VB DataGrid10.aspx

[Run Sample] | [View Source]


Sorting Data from a SQL Database

A common requirement for any grid is the ability to sort the data it contains. While the DataGrid control doesn't explicitly sort its data for you, it does provide a way to call an event handler when the user clicks a column header, which you can use to sort the data. When the DataGrid's AllowSorting property is set to true, it renders hyperlinks for the column headers that fire a Sort command back to the grid. You set the OnSortCommand property of the DataGrid to the handler you want to call when the user clicks a column link. The name of the column is passed as a SortExpression property on the DataGridSortCommandEventArgs argument, which you can use to set the Sort property of the DataView bound to the grid. The following example demonstrates this process.

VB

The following sample shows this code in action.

 
VB DataGrid11.aspx

[Run Sample] | [View Source]

When using BoundColumn controls, you can explicitly set the SortExpression property for each column, as demonstrated in the following sample.

 
VB DataGrid12.aspx

[Run Sample] | [View Source]


Working with Master-Detail Relationships

Often your data model will contain relationships that cannot be represented using just a single grid. A very common Web-based interface is one in which a row of data can be selected that navigates the client to a "details" page, which displays detailed information about the selected row. To accomplish this using the DataGrid, you can add a HyperLinkColumn to the Columns collection, which specifies the details page to which the client will navigate when the link is clicked. You use the format string syntax to substitute a field value in this link, which is passed as a querystring argument. The following example demonstrates this process.

On the details page, you retrieve the querystring argument and perform a join select to obtain details from the database. The following sample demonstrates this scenario.

 
VB DataGrid13.aspx

[Run Sample] | [View Source]


Writing and Using Stored Procedures

In general, performing ad hoc queries comes at the expense of performance. Using stored procedures can reduce the cost of performing heavy database operations in an application. A stored procedure is easy to create, and can even be done using a SQL statement. The following code example creates a stored procedure that simply returns a table.

You can create stored procedures that accept parameters as well. For example:

CREATE Procedure LoadPersonalizationSettings (@UserId varchar(50)) AS
    SELECT * FROM Personalization WHERE UserID=@UserId
    return
GO

Using a stored procedure from an ASP.NET page is just an extension of what you've learned so far about the SqlCommand object. The CommandText is just the name of the stored procedure instead of the ad hoc query text. You indicate to the SqlCommand that the CommandText is a stored procedure by setting the CommandType property.


myCommand.SelectCommand.CommandType = CommandType.StoredProcedure
VB

The following sample demonstrates a call to a stored procedure to fill the DataSet.

 
VB DataGrid14.aspx

[Run Sample] | [View Source]

Parameters to stored procedures are passed just as they are for ad hoc queries, as shown in the following samples.

 
VB DataGrid15.aspx

[Run Sample] | [View Source]

 
VB DataGrid16.aspx

[Run Sample] | [View Source]


Accessing XML-based Data

At the beginning of this section it was mentioned that the DataSet was designed to abstract data in a way that is independent of the actual data source. You can see this by changing the focus of your samples from SQL to XML. The DataSet supports a ReadXml method that takes a FileStream object as its parameter. The file you read in this case must contain both a schema and the data you wish to read. The DataSet expects data to be in the form, as shown in the following example.

Each TableName section corresponds to a single row in the table. The following sample shows reading schema and data from an XML file using the ReadXml method of the DataSet. Note that after the data is read into the DataSet it is indistinguishable from SQL data -- the DataGrid binds to it just the same, as shown in the following sample.

 
VB DataGrid17.aspx

[Run Sample] | [View Source]

You can also read the data and schema separately, using the ReadXmlData and ReadXmlSchema methods of the DataSet, as shown in the following sample.

 
VB DataGrid18.aspx

[Run Sample] | [View Source]

Just as the DataSet supports reader methods for XML data, it also supports writing the data. The following sample implements a tool for selecting data from SQL and writing the result as XML data or schema text.

 
VB XMLGen.aspx

[Run Sample] | [View Source]

Section Summary

  1. The common language runtime's managed data access APIs abstract data and present it in a consistent way regardless of its actual source (SQL Server, OLEDB, XML, and so on).
  2. To give your page access to the classes you will need to perform SQL data access, you must import the System.Data and System.Data.SqlClient namespaces into your page.
  3. Populating a dataset from a SQL query involves creating a SqlConnection, associating a SqlDataAdapter object with the connection that contains your query statement, and filling the dataset from the command.
  4. The DataGrid control supports a DataSource property that takes an IEnumerable (or ICollection) type. You can set this to the result of a SQL query by assigning the DataSet's DefaultView property, which is of type DataView.
  5. The SqlDataAdapter maintains a Parameters collection that can be used to replace variable identifiers (denoted by an "@" in front of the name) with values.
  6. When performing commands that do not require data to be returned, such as inserts, updates, and deletes, you use a SqlCommand instead of the SqlDataAdapter. The command is issued by calling an ExecuteNonQuery method, which returns the number of rows affected.
  7. The SqlConnection must be explicitly opened when you use the SqlCommand (the SqlDataAdapter automatically handles opening the connection for you). Always remember to close the SqlConnection to the data model before the page finishes executing. If you do not close the connection, you migh inadvertantly exhaust the connection limit while waiting for the page instances to be released to garbage collection.
  8. To allow rows to be edited, the DataGrid supports an integer EditItemIndex property, which indicates which row of the grid should be editable. When this property is set, the DataGrid renders the row at that index as text input boxes instead of simple labels.
  9. The DataGrid exposes a DataKeyField property that you can set to the field name for the primary key. In the event handler wired to the UpdateCommand, you can retrieve the key name from the DataGrid's DataKeys collection.
  10. Using BoundColumn controls in the DataGrid gives you complete control over the order of the columns, as well as their ReadOnly properties.
  11. Using TemplateColumn controls in the DataGrid gives you complete control over the contents of the column.
  12. The ButtonColumn control can be used to simply render a button control in each row for that column, which can be associated with an event.
  13. A HyperLinkColumn can be added to the DataGrid's Columns collection, which supports navigating to another page when the link is clicked.
  14. When the DataGrid's AllowSorting property is set to true, it renders hyperlinks for the column headers that fire a Sort command back to the grid. You set the OnSortCommand property of the DataGrid to the handler you want to call when the user clicks a column link.
  15. The DataSet supports ReadXml, ReadXmlData, and ReadXmlSchema methods that take a FileStream as a parameter, which can be used to populate a DataSet from an XML file.
  16. Using stored procedures can reduce the cost of performing heavy database operations in an application.


Copyright 2001 Microsoft Corporation. All rights reserved.