7.2 Data Binding Controls
Many server controls in ASP.NET support data binding for populating their contents. These controls expose a
DataSource
property to be
Figure 7-2. Controls Capable of Data Binding, and Some Common Collections to Bind To
Note that the list of data sources includes many collection classes in addition to the ADO.NET classes. This means that binding data to a control does not
Listing 7-2 Binding an ArrayList to Several Server Controls
<!-- File: ArrayListBind.aspx -->
<%@ Page Language="VB" %>
<html><body>
<head>
<script runat=server>
Protected Sub Page_Load(sender As Object, e As EventArgs)
Dim vals As ArrayList = new ArrayList()
vals.Add("v1")
vals.Add("v2")
vals.Add("v3")
vals.Add("v4")
s1.DataSource = vals
cbl1.DataSource= vals
dd1.DataSource = vals
lb1.DataSource = vals
rbl1.DataSource= vals
DataBind()
End Sub
</script>
</head>
<form runat=server>
<Select id="s1" runat=server /><br/>
<asp:DropDownList id="dd1" runat=server /><br/>
<asp:CheckBoxList id="cbl1" runat=server /><br/>
<asp:ListBox id="lb1" runat=server /><br/>
<asp:RadioButtonList id="rbl1" runat=server /><br/>
</form>
</body> </html>
Figure 7-3. ArrayListBind.aspx Page Instance
|
7.3 Binding to Database Sources
As we have seen, it is possible to bind to many different types of collections in .NET. The most common type of binding by far, however, is to bind to a result set retrieved from a database query. ADO.NET provides two ways of retrieving result sets from a database: the streaming
IDataReader
interface and the disconnected
DataSet
class. We will look at each of these in
7.3.1 IDataReader BindingThe most efficient way to retrieve data for binding from a database is to use the streaming IDataReader interface from ADO.NET. This interface provides access to the results of a query in a stream, in forward-only fashion, and makes no additional copy of the data. In all the existing ADO.NET data providers, the data reader implementation classes also support IEnumerable so that they are compatible with data binding, and in general, it should be safe to assume that any data reader implementation provides an IEnumerable interface implementation as well.
In our first example of using a data reader, shown in Listing 7-1, we bound to a
DataGrid
, which provides a tabular rendering of the data. If you are trying to bind a data reader to a single column control such as a
ListBox
or a
DropDownList
, however, it is ambiguous which fields of the result set should be mapped to the strings and values of the control. To deal with this, controls like the
DropDownList
define two additional fields:
DataTextField
and
DataValueField.
These fields can be
Listing 7-3 Binding a Data Reader to a DropDownList
<!-- File: DataReaderBind.aspx -->
<%@Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<script runat="server">
Protected Sub Page_Load(src As Object, e As EventArgs)
If Not IsPostBack Then
Dim conn As IDbConnection
conn = _
New SqlConnection("server=.;uid=sa;pwd=;database=Pubs")
Dim cmd As IDbCommand = conn.CreateCommand()
cmd.CommandText = "SELECT * FROM Authors"
Try
conn.Open()
Dim reader As IDataReader = cmd.ExecuteReader()
_authors.DataSource = reader
_authors.DataTextField = "au_lname"
_authors.DataValueField = "au_id"
_authors.DataBind()
Finally
conn.Dispose()
End Try
Else
_message.Text = _
string.Format("You selected employee #{0}", _
_authors.SelectedItem.Value)
End If
End Sub
</script></head>
<form runat=server>
<asp:DropDownList id="_authors" runat=server />
<br/>
<asp:Label id="_message" runat=server/>
<br/>
<input type=submit value="Submit" />
</form>
</body>
</html>
In this example, we are only populating the
DropDownList
control if the incoming request is the initial
GET
request to the page, not a
Figure 7-4. DataReaderBind.aspx Page Running
7.3.2 DataSet BindingIt is also common to bind DataSet s to controls for display. Because a DataSet can represent the results of multiple database queries, however, you need to specify which portion of the DataSet should be used for binding. If you simply bind to the entire DataSet , the default view of the first table in the DataSet is used. If you want more control over which table within a DataSet to use during binding, data-bound controls support an additional field, DataMember , that indicates which "set" of data to bind to the control. For a DataSet , this means which table to bind. Alternatively, you can be explicit about it and bind to a table within a DataSet , in which case the default view of that table is used. Or you can be even more explicit and use the DataView that provides a "view" into a data set and can be created with custom sorting and filtering rules.
Listing 7-4 shows an example of binding data from a
DataSet
to a pair of controls. Note that the first control is bound directly to the
DataSet
, which implicitly binds to the default view of the
DataSet
. The second control is bound to an explicitly created
DataView
, whose
Filter
property has been
Listing 7-4 Binding to a DataView
<!-- File: DataViewBind.aspx -->
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<script runat="server">
Protected Sub Page_Load(src As Object, e As EventArgs)
If Not IsPostBack Then
Dim conn As IDbConnection
conn = _
New SqlConnection("server=.;uid=sa;pwd=;database=Pubs")
Dim da As SqlDataAdapter
da = New SqlDataAdapter("select * from Authors", conn)
Dim ds As DataSet = New DataSet()
da.Fill(ds, "Authors")
_lb1.DataSource = ds
_lb1.DataTextField = "au_lname"
_lb1.DataValueField = "au_id"
Dim view As DataView
view = New DataView(ds.Tables("Authors"))
view.RowFilter = "au_lname like 'G%'"
view.Sort = "au_lname"
_lb2.DataSource = view
_lb2.DataTextField = "au_lname"
_lb2.DataValueField = "au_id"
DataBind()
Else
_message.Text = _
string.Format("LB1 = {0}, LB2 = {1}", _
_lb1.SelectedItem.Value, _
_lb2.SelectedItem.Value)
End If
End Sub
</script>
<body>
<form runat=server>
<asp:ListBox id="_lb1" runat=server /> <br/>
<asp:ListBox id="_lb2" runat=server /> <br/>
<asp:Label id="_message" runat=server/> <br/>
<input type=submit value="Submit"/>
</form>
</body>
</html>
The biggest difference between binding to a DataSet and binding to data readers is that the DataSet makes a local copy of the data, and the connection to the database is closed immediately after the call to the Sql-Data Adapter.Fill() method completes. Figure 7-5 shows the DataView- Bind.aspx page running. Figure 7-5. DataViewBind.aspx Page Instance
7.3.3 DataSet versus DataReader for Data Binding
As we have seen, both the
DataSet
and the
DataReader
can be used to bind data to a control, but when should you choose one over the other? A good rule of thumb to answer this question is, if you are not taking advantage of the
DataSet
's cache of the data, you should probably use a
DataReader
. If you use a
DataSet
simply to retrieve data from a data source and then immediately bind it to a control, subsequently
In addition, because data-bound controls guarantee that they will retain any data you bind to them, even across post-backs, it is quite easy to generate three distinct copies of the data in-memory in the server, which can be
Figure 7-6. The Hazards of Na ve Data Binding
To avoid this duplication of data during data binding, you can take two steps. First, use a
DataReader
in place of a
DataSet
when you are doing nothing with the data but binding it to a control. Second, disable the view state of the data-bound control by setting the control's
EnableViewState
flag to
false
(although there are caveats to doing this, discussed later). Performing both of these steps
Figure 7-7. Efficient Data Binding
Unfortunately, you cannot always disable the view state of a control without
There are also occasions where using the
DataSet
makes more sense than using a
DataReader
. As mentioned earlier, if you are taking advantage of the fact that the
DataSet
creates a local cache of the data, by all means use it. One case in which to consider a
DataSet
is when you bind one set of data to multiple controls,
|