Tải bản đầy đủ (.pdf) (10 trang)

Professional ASP.NET 3.5 in C# and Visual Basic Part 48 potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (338.54 KB, 10 trang )

Evjen c08.tex V2 - 01/28/2008 2:05pm Page 426
Chapter 8: Data Management with ADO.NET
After you close the Add Table dialog box, you see a visual representation of the table that you selected in
the Query Builder dialog box (see Figure 8-19). You can then select some or all the fields to be returned
from the query. For this example, you want everything returned from both the Customers and the Orders
table, so select the first check box with the asterisk (
*
). Notice that the query listed in this dialog box now
says
SELECT * FROM Customers
. After the word ‘‘Customers,’’ add text to the query so that it looks like
the following:
SELECT Customers.* FROM Customers WHERE (CustomerID LIKE @Customer)
With this query, you specify that you want to return the customer information when the
CustomerID
fits
the parameter that you pass into the query from your code (using
@Customer
).
After your query is in place, simply click OK and then click the Next button to have not only the
select
query, but also the
insert
,
update
,and
delete
queries generated for you.
Figure 8-20 shows you the final page after all the queries have been generated.
Figure 8-20
426


Evjen c08.tex V2 - 01/28/2008 2:05pm Page 427
Chapter 8: Data Management with ADO.NET
After you reach this point, you can either click the Previous button to return to one of the prior steps
in order to change a setting or the query itself, or you can click the Finish button to apply everything
to your TableAdapter. After you are finished using the wizard, notice there is a visual representation
of the
CustomersTableAdapter
that you just created (see Figure 8-21). Along with that is a
DataTable
object for the Customers table. The
TableAdapter
and the
DataTable
objects that are shown on the
design surface are also labeled with their IDs. Therefore, in your code, you can address this TableAdapter
that you just built by referring to it as
CustomerOrdersTableAdapters.CustomersTableAdapter
.The
second TableAdapter that queries the Orders table is then shown and referred to as
CustomerOrders-
TableAdapters.OrdersTableAdapter
.
Figure 8-21
After you have the two DataAdapters in place, you will also notice that there is an automatic relation put
into place for you. This is represented by the line between the two items on the page. Right-clicking on
the relation, you can edit the relation with the Relation dialog box (see Figure 8-22).
In the end, Visual Studio has taken care of a lot for you. Again, this is not the only way to complete all
these tasks.
Using the CustomerOrders DataSet
Now comes the fun part — building the ASP.NET that will use all the items that were just created! The

goal is to allow the end user to send in a request that contains just the CustomerID. In return, he will
427
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 428
Chapter 8: Data Management with ADO.NET
get back a complete DataSet containing not o nly the customer information, b ut also all the relevant
order information. Listing 8-29 shows you the code to build all this functionality. You need only a single
method in addition to the
Page_Load
:the
GetCustomerOrders()
method. The page should be laid out as
is shown here in Figure 8-23.
Figure 8-22
The page that you create should contain a single TextBox control, a Button control, and two GridView
controls (GridView1 and GridView2). The code for the page is shown in Listing 8-29.
428
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 429
Chapter 8: Data Management with ADO.NET
Figure 8-23
Listing 8-29: The .aspx page
<
%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb"
Inherits="_Default" %
>
<
html xmlns=" />>
<
head runat="server"
>
<

title
>
CustomerOrders
<
/title
>
<
/head
>
<
body
>
<
form id="form1" runat="server"
>
<
div
>
Enter Customer ID:
<
asp:TextBox ID="TextBox1" runat="server"
><
/asp:TextBox
>
<
br /
>
Continued
429
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 430

Chapter 8: Data Management with ADO.NET
<
asp:Button ID="Button1" runat="server" Text="Select" /
>
<
br /
>
<
br /
>
<
asp:GridView ID="GridView1" runat="server" BackColor="White"
BorderColor="#999999" BorderStyle="Solid" BorderWidth="1px"
CellPadding="3" ForeColor="Black" GridLines="Vertical"
>
<
FooterStyle BackColor="#CCCCCC" /
>
<
PagerStyle BackColor="#999999" ForeColor="Black"
HorizontalAlign="Center" /
>
<
SelectedRowStyle BackColor="#000099" Font-Bold="True"
ForeColor="White" /
>
<
HeaderStyle BackColor="Black" Font-Bold="True" ForeColor="White" /
>
<

AlternatingRowStyle BackColor="#CCCCCC" /
>
<
/asp:GridView
>
<
br /
>
<
asp:GridView ID="GridView2" runat="server" BackColor="White"
BorderColor="#999999" BorderStyle="Solid" BorderWidth="1px"
CellPadding="3" ForeColor="Black" GridLines="Vertical"
>
<
FooterStyle BackColor="#CCCCCC" /
>
<
PagerStyle BackColor="#999999" ForeColor="Black"
HorizontalAlign="Center" /
>
<
SelectedRowStyle BackColor="#000099" Font-Bold="True"
ForeColor="White" /
>
<
HeaderStyle BackColor="Black" Font-Bold="True" ForeColor="White" /
>
<
AlternatingRowStyle BackColor="#CCCCCC" /
>

<
/asp:GridView
>
<
/div
>
<
/form
>
<
/body
>
<
/html
>
The code-behind for the page is presented in Listing 8-30.
Listing 8-30: The code-behind for the CustomerOrders page
VB
Imports System
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
If Page.IsPostBack Then
GetCustomerOrders(TextBox1.Text)
End If
End Sub
Protected Sub GetCustomerOrders(ByVal custId As String)
Dim myDataSet As New CustomerOrders
Dim custDA As New CustomerOrdersTableAdapters.CustomersTableAdapter

Dim ordersDA As New CustomerOrdersTableAdapters.OrdersTableAdapter
430
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 431
Chapter 8: Data Management with ADO.NET
custDA.Fill(myDataSet.Customers, custId)
ordersDA.Fill(myDataSet.Orders, custId)
myDataSet.Customers(0).Phone = "NOT AVAILABLE"
myDataSet.Customers(0).Fax = "NOT AVAILABLE"
GridView1.DataSource = myDataSet.Tables("Customers")
GridView1.DataBind()
GridView2.DataSource = myDataSet.Tables("Orders")
GridView2.DataBind()
End Sub
End Class
C#
using System;
using CustomerOrdersTableAdapters;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
GetCustomerOrders(TextBox1.Text);
}
}
protected void GetCustomerOrders(string custId)
{
CustomerOrders myDataSet = new CustomerOrders();
CustomersTableAdapter custDA = new CustomersTableAdapter();

OrdersTableAdapter ordersDA = new OrdersTableAdapter();
custDA.Fill(myDataSet.Customers, custId);
ordersDA.Fill(myDataSet.Orders, custId);
myDataSet.Customers[0].Phone = "NOT AVAILABLE";
myDataSet.Customers[0].Fax = "NOT AVAILABLE";
GridView1.DataSource = myDataSet.Tables["Customers"];
GridView1.DataBind();
GridView2.DataSource = myDataSet.Tables["Orders"];
GridView2.DataBind();
}
}
Now there is not much code here. One of the first things done in the method is to create an instance of
the typed DataSet. In the next two lines of code, the
custDA
and the
ordersDA
objects are used. In this
case, the only accepted parameter,
custId
, is being set for both the DataAdapters. After this parameter
is passed to t he TableAdapter, this TableAdapter queries the database based upon the
select
query that
you programmed into it earlier using the TableAdapter wizard.
431
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 432
Chapter 8: Data Management with ADO.NET
After the query, the TableAdapter is instructed to fill the instance of the DataSet. Before the DataSet
is returned to the consumer, you can change how the result is output to the client. If you are pass-
ing customer information, you may want to exclude some of the information. Because the DataSet is

a typed DataSet, you have programmatic access to the tables. In this example, the code specifies that in
the DataSet, in t he Customers table, in the first row (remember it is zero-based), make the value of the
Phone and Fax fields equal to
NOT AVAILABLE
.
By compiling and running the ASP.NET page, you are able to test it from the test page using the Cus-
tomerID of ALFKI (the first record of the Customers table in the Northwind database). T he results are
returned to you in the browser (see Figure 8-24).
Figure 8-24
Asynchronous Command Execution
When you process data using ADO or previous versions of ADO.NET, each command is executed
sequentially. The code waits for each command to complete before the next one is processed. When
you use a single database, the sequential processing enables you to reuse the same connection object for
all commands. However, with the introduction of MARS, you can now use a single connection for mul-
tiple, concurrent database access. Since the introduction of ADO.NET 2.0, ADO.NET has enabled users
to process database commands asynchronously. This enables you to not only use the same connection,
but also to use it in a parallel manner. The real advantage of asynchronous processing becomes apparent
432
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 433
Chapter 8: Data Management with ADO.NET
when you are accessing multiple data sources — especially when the data access queries across these
databases aren’t dependent on each other. Y ou can now open a connection to the database in an asyn-
chronous manner. When you are working with multiple databases, you can now open connections to
them in a parallel fashion as well.
Tomakethiswork,besuretoadd
Asynchronous Processing = true;
to your connection string.
Asynchronous Methods of the SqlCommand Class
The
SqlCommand

class provides a few additional methods that facilitate executing commands asyn-
chronously. These new methods are summarized in the following table.
Method Description
BeginExecute-
NonQuery()
This method expects a query that doesn’t return any results and starts it
asynchronously. The return value is a reference to an object of the
SqlAsyncResult
class that implements the
IAsyncResult
interface. The
returned object can be used to monitor the process as it runs and when it is
completed.
BeginExecuteNonQuery
(callback,
stateObject )
This overloaded method also starts the process asynchronously, and it
expects to receive an object of the
AsynchCallback
instance. The callback
method is called after the process is finished running so that you can
proceed with other tasks. The second parameter receives any
custom-defined object. This object is passed to the callback automatically.
It provides an excellent mechanism for passing parameters to the callback
method. The callback method can retrieve the custom-defined state object
by using the
AsyncState
property of the
IAsyncResult
interface.

EndExecuteNonQuery
(asyncResult)
This method is used to access the results from the
BeginExecuteNonQuery
method. When calling this method, you are required to pass the same
SqlAsyncResult
object that you received when you called the
BeginExecuteNonQuery
method. This method returns an integer value
containing the number o f rows affected.
BeginExecuteReader
This method expects a query that returns a result set and starts it
asynchronously. The return value is a reference to an object of
SqlAsyncResult
class that implements
IAsyncResult
interface. The
returned object can be used to monitor the process as it runs and as it is
completed.
BeginExecuteReader
(commandBehavior)
This overloaded method works the same way as the one described
previously. It also takes a parameter containing a command behavior
enumeration just like the synchronous
ExecuteReader
method.
BeginExecuteReader
(callback,
stateObject)
This overloaded method starts the asynchronous process and it expects to

receive an object of
AsyncCallback
instance. The callback method is called
after the process finishes running so that you can proceed with other tasks.
The second parameter receives any custom-defined object. This object is
passed to the callback automatically. It provides an excellent mechanism
for passing parameters to the callback method. The callback method can
retrieve the custom-defined state object by using the
AsyncState
property
of the
IAsyncResult
interface.
433
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 434
Chapter 8: Data Management with ADO.NET
Method Description
BeginExecuteReader
(callback,
stateObject,
commandBehavior)
This overloaded method takes an instance of the
AsyncCallback
class and
uses it to fire a callback method when the process has finished running.
The second parameter receives a custom object to be passed to the callback
method, and the third parameter uses the command behavior enumeration
in the same way as the synchronous
ExecuteReader
method.

EndExecuteReader
This method is used to access the results from the
BeginExecuteReader
method. When calling this method, you are required to pass the same
SqlAsyncResult
object that you receive when you called the
BeginExecuteReader
method. This method returns a
SqlDataReader
object containing the result of the SQL query.
BeginExecute-
XmlReader
This method expects a query that returns the result set as XML. The return
value is a reference to an object of
SqlAsyncResult
class that implements
IAsyncResult
interface. The returned object can be used to monitor the
process as it runs and as it is completed.
BeginExecute-
XmlReader (callback,
stateObject)
This overloaded method starts the asynchronous process, and it expects to
receive an object of
AsyncCallback
instance. The callback method is called
after the process has finished running so that you can proceed with other
tasks. The second parameter receives any custom-defined object. This
object is passed to the callback automatically. It provides an excellent
mechanism for passing parameters to the callback method. The callback

method can retrieve the custom-defined state object by using the
AsyncState
property of the
IAsyncResult
interface.
EndExecuteXmlReader
This method is used to access the results from the
BeginExecuteXmlReader
method. When calling this method, you are required to pass the same
SqlAsyncResult
object that you received when you called the
BeginExecuteXmlReader
method. This method returns an XML Reader
object containing the result of the SQL query.
IAsyncResult Interface
All the asynchronous methods for the
SqlCommand
class return a reference to an object that exposes the
IAsyncResult
interface. The properties of this interface are shown in the following table.
Property Description
AsyncState
This read-only property returns an object that describes the state of the process.
AsyncWaitHandle
This read-only property returns an instance of
WaitHandle
that can be used to
set the time out, test whether the process has completed, and force the code to
wait for completion.
Completed-

Synchronously
This read-only property returns a Boolean value that indicates whether the
process was executed synchronously.
IsCompleted
This read-only property returns a Boolean value indicating whether the process
has completed.
434
Evjen c08.tex V2 - 01/28/2008 2:05pm Page 435
Chapter 8: Data Management with ADO.NET
AsyncCallback
Some of the asynchronous methods of the
SqlCommand
class receive an instance of the
AsyncCallback
class. This class is not specific to ADO.NET and is used by many objects in the .NET Framework. It is
used to specify those methods that you want to execute after the asynchronous p rocess has finished
running. This class uses its constructor to receive the address of the method that you want to use for
callback purposes.
WaitHandle Class
This class is an abstract class used for multiple purposes such as causing the execution to wait for any
or all asynchronous processes to finish. To process more than one database command asynchronously,
you can simply create an array containing wait handles for each asynchronous process. Using the static
methods of the
WaitHandle
class, you can cause the execution to wait for either any o r all wait handles
in the array to finish processing.
The
WaitHandle
class exposes a few methods, as shown in the following table.
Method Description

WaitOne
This method waits for a single asynchronous process to complete or time
out. It returns a Boolean value containing
True
if the process completed
successfully and
False
if it timed out.
WaitOne
(milliseconds
,
exitContext)
This overloaded method receives an integer value as the first parameter.
This value represents the time out in milliseconds. The second parameter
receives a Boolean value specifying whether the method requires
asynchronous context and should be set to
False
for asynchronous
processing.
WaitOne (timeSpan
,
exitContext)
This overloaded method receives a
TimeSpan
object to represent the
time-out value. The second parameter receives a Boolean value specifying
whether the method requires asynchronous context and should be set to
False
for Asynchronous processing.
WaitAny

(waitHandles)
This is a static method used if you are managing more than one
WaitHandle
in the form of an array. Using this method causes the
execution to wait for any of the asynchronous processes that have been
started and whose wait handles are in the array being passed to it. The
WaitAny
method must be called repeatedly — once for each
WaitHandle
you want to process.
WaitAny (waitHandles
,
milliseconds
,
exitContext)
This overloaded method receives the time-out value in the form of
milliseconds and a Boolean value specifying whether the method requires
asynchronous context. It should be set to
False
for asynchronous
processing.
WaitAny (waitHandles
,
timeSpan,
exitContext
This overloaded method receives the time-out value in the form of a
TimeSpan
object. The second parameter receives a Boolean value specifying
whether the method requires asynchronous context. It should be set to
False

for asynchronous processing.
WaitAll
(waitHandles)
This is a static method and is used to wait for all asynchronous processes
to finish running.
435

×