5.3. The DataReader
Once you've defined your
command, you need to decide how you want to use it. The simplest
approach is to use a DataReader, which allows you to quickly retrieve
all your results. The DataReader uses a live connection and should be
used quickly and then closed. The DataReader is also extremely simple.
It supports fast-forward-only read-only access to your results, which is
generally all you need when retrieving information. Because of the
DataReader's optimized nature, it provides better performance than the
DataSet. It should always be your first choice for direct data access.
Before you can use a DataReader, make sure you've opened the connection:
myConnection.Open()
To create a DataReader, you use the ExecuteReader() method of the command object, as shown here:
' You don't need the new keyword, as the Command will create the DataReader.
Dim myReader As SqlDataReader
myReader = myCommand.ExecuteReader()
These two lines of code define a
variable for a DataReader and then create it by executing the command.
Once you have the reader, you retrieve a single row at a time using the
Read() method:
myReader.Read() ' The first row in the result set is now available.
You can then access the
values in the current row using the corresponding field names. The
following example adds an item to a list box with the first name and
last name for the current row:
lstNames.Items.Add(myReader("au_lname") & ", " & myReader("au_fname"))
To move to the next row, use
the Read() method again. If this method returns True, a row of
information has been successfully retrieved. If it returns False, you've
attempted to read past the end of your result set. There is no way to
move backward to a previous row.
As soon as you've finished reading all the results you need, close the DataReader and Connection:
myReader.Close()
myConnection.Close()
5.4. Putting It All Together
The next example demonstrates
how you can use all the ADO.NET ingredients together to create a simple
application that retrieves information from the Authors table. You can
select an author record by last name using a drop-down list box, as
shown in Figure 10.
The full record is then retrieved and displayed in a simple label, as shown in Figure 11.
5.4.1. Filling the List Box
To start, the connection string is defined as a private variable for the page class and retrieved from the connection string:
Private connectionString As String = _
WebConfigurationManager.ConnectionStrings("Pubs").ConnectionString
The list box is filled when
the Page.Load event occurs. Because the list box is set to persist its
view state information, this information needs to be retrieved only
onceāthe first time the page is displayed. It will be ignored on all
postbacks.
Here's the code that fills the list from the database:
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
FillAuthorList()
End If
End Sub
Private Sub FillAuthorList()
lstAuthor.Items.Clear()
' Define the Select statement.
' Three pieces of information are needed: the unique id
' and the first and last name.
Dim selectSQL As String = "SELECT au_lname, au_fname, au_id FROM Authors"
' Define the ADO.NET objects.
Dim con As New SqlConnection(connectionString)
Dim cmd As New SqlCommand(selectSQL, con)
Dim reader As SqlDataReader
' Try to open database and read information.
Try
con.Open()
reader = cmd.ExecuteReader()
' For each item, add the author name to the displayed
' list box text, and store the unique ID in the Value property.
Do While reader.Read()
Dim newItem As New ListItem()
newItem.Text = reader("au_lname") & ", " & reader("au_fname")
newItem.Value = reader("au_id").ToString()
lstAuthor.Items.Add(newItem)
Loop
reader.Close()
Catch err As Exception
lblResults.Text = "Error reading list of names."
lblResults.Text &= err.Message
Finally
con.Close()
End Try
End Sub
It uses the standard
Connection, Command, and DataReader objects. The Connection is opened
inside an error handling block so your page can handle any unexpected
errors and provide information. A Finally block makes sure the
connection is properly closed, even if an error occurs.
The actual code for reading
the data uses a loop. With each pass, the Read() method is called to
get another row of information. When the reader has read all the
available information, this method will return False, the loop condition
will evaluate to False, and the loop will end gracefully.
The unique ID (the value in
the au_id field) is stored in the Value property of the list box for
reference later. This is a crucial ingredient that is needed to allow
the corresponding record to be queried again. If you tried to build a
query using the author's name, you would need to worry about authors
with the same name. You would also have the additional headache of
invalid characters (such as the apostrophe in O'Leary) that would
invalidate your SQL statement.
5.4.2. Retrieving the Record
The record is retrieved as soon
as the user changes the selection in the list box. To make this
possible, the AutoPostBack property of the list box is set to True so
that its change events are detected automatically.
Protected Sub lstAuthor_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles lstAuthor.SelectedIndexChanged
' Create a Select statement that searches for a record
' matching the specific author ID from the Value property.
Dim selectSQL As String
selectSQL = "SELECT * FROM Authors "
selectSQL &= "WHERE au_id='" & lstAuthor.SelectedItem.Value & "'"
' Define the ADO.NET objects.
Dim con As New SqlConnection(connectionString)
Dim cmd As New SqlCommand(selectSQL, con)
Dim reader As SqlDataReader
' Try to open database and read information.
Try
con.Open()
reader = cmd.ExecuteReader()
reader.Read()
' Build a string with the record information,
' and display that in a label.
Dim sb As New StringBuilder()
sb.Append("<b>")
sb.Append(reader("au_lname"))
sb.Append(", ")
sb.Append(reader("au_fname"))
sb.Append("</b><br />")
sb.Append("Phone: ")
sb.Append(reader("phone"))
sb.Append("<br />")
sb.Append("Address: ")
sb.Append(reader("address"))
sb.Append("<br />")
sb.Append("City: ")
sb.Append(reader("city"))
sb.Append("<br />")
sb.Append("State: ")
sb.Append(reader("state"))
sb.Append("<br />")
lblResults.Text = sb.ToString()
reader.Close()
Catch err As Exception
lblResults.Text = "Error getting author. "
lblResults.Text &= err.Message
Finally
con.Close()
End Try
End Sub
The process is similar to the procedure used to retrieve the last names. There are only a couple of differences:
The code dynamically
creates a SQL statement based on the selected item in the drop-down list
box. It uses the Value property of the selected item, which stores the
unique identifier. This is a common (and useful) technique.
Only
one record is read. The code assumes that only one author has the
matching au_id, which is reasonable since this field is unique.
NOTE
This
example shows how ADO.NET works to retrieve a simple result set. Of
course, ADO.NET also provides handy controls that go beyond this generic
level and let you provide full-featured grids with sorting and editing.