Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP .NET Web Developer s Guide - Mesbah Ahmed, Chris Garrett

.pdf
Скачиваний:
37
Добавлен:
24.05.2014
Размер:
7.32 Mб
Скачать

300 Chapter 7 • Introduction to ADO.NET: A Simple Address Book

Introduction

ADO.NET is the latest implementation of Microsoft’s universal data access strategy. In the past few years we have gone through many changes to classic ADO as Microsoft made changes, bug-fixes, and enhancements to the venerable libraries. These libraries have made the foundation for many Web sites and applications that are in place today.ADO.NET will be no different in this respect, as Microsoft is positioning ADO.NET to be the primary data access technology for the .NET Framework.This will ensure that the data access architecture is mature and robust, since all the Common Language Runtime (CLR) languages will be using these namespaces for their primary means of communicating with data providers.

Flexible and efficient data access technologies are at the heart of dynamic Web sites and Web applications. Classic ADO serialized data in a proprietary protocol that limited its reach, and it could have been made more efficient. ADO.NET serializes data using XML.This allows ADO.NET to take advantage of a standards-based approach to moving data back and forth in your applications. With rich support for any data source that can create or consume XML, ADO.NET is truly the data access technology for current and future applications. Through ADO.NET, you are able to connect to a myriad of data sources with the speed and flexibility that today’s businesses require.

The goal for the developers of the ADO.NET architecture is to continue the tradition of ADO by further removing the complexities of interacting with different data providers, and shielding you from the intricacies that would interfere with the primary mission—packing functionality and usefulness into your applications.

This chapter will delve into the common strategies for viewing, editing, and deleting data in the various ways that ADO.NET allows.The primary data source for the examples will be SQL Server 2000, with Access 2002 as an alternative. The sample application is a straightforward address book.The architecture of our sample is very simple, in order to allow us to concentrate on the task at hand.We will step through the application and discuss some of the best uses of ADO.NET.

Understanding the Changes in ADO.NET

As mentioned above, ADO.NET has a relatively long history. As far as software development goes, if you are going to make dramatic enhancements, it is sometimes necessary to start from scratch, taking what you learned from the last implementation and looking forward with wisdom and clairvoyance. More than

www.syngress.com

Introduction to ADO.NET: A Simple Address Book • Chapter 7

301

likely, it will result in a product that is not backward compatible and that requires significant change to bring older applications up to par.

The same could be said for ADO.NET. It is a vast departure in some ways, but not in others. Suffice to say that you will have to change your existing code to make it work in the ADO.NET world.

To start with, let us talk about the foundation. ADO.NET has taken XML to heart with rich support for XML data, both as a data consumer and as a data provider. Later versions of classic ADO had some support for XML, but the format was difficult to use unless you were exchanging it with another ADO client.The XML documents that ADO.NET creates are consistent with the XML specification and are what is known as “well-defined documents,” making them suitable for consumption by any data access technology that understands XML. You can take a plain XML document with just a root node and open it in ADO.NET, add data to it, and save it back out.

The Recordset is dead. ADO.NET has a couple of new ways to serve data, which made the Recordset obsolete.These new objects are the DataSet and the DataReader. The DataSet has really made the classic ADO Recordset object obsolete by providing functionality that goes far beyond what the Recordset was able to provide. At the heart of the Recordset was the cursor.The classic ADO connection and Recordset objects both had a property to set the location of the cursor, either client-side or server-side.This provided a source for confusion, and enabled programmers to open scrolling, updatable cursors directly on the database server.This type of cursor is very expensive for the server to create and maintain. Scrolling, updatable cursors definitely have their uses, and will continue to fill a niche in data access applications.

The DataSet is really an in-memory relational database.The block diagram in Figure 7.1 shows the many collections in a DataSet, namely the DataTables collection, DataViews collection, and DataRelations collection. A programmer will create one or more DataTable objects in a DataSet and “fill” them with data. A DataTable contains a collection of DataRows, each of which contains a collection of DataColumns.We can optionally create DataViews based on these DataTables, and even define relations to enforce data integrity. Again with all this functionality we really don’t have the need for a Recordset object.

The process of filling a DataTable with data is simple, and provides us with a copy of the data from the data source.The DataSet does not maintain a connection to the data source.With this copy of our data, the application can enable the user to add, edit, and remove data.The application can then enable the user to save this data back to the original data source. As a matter of fact, this data can be

www.syngress.com

302 Chapter 7 • Introduction to ADO.NET: A Simple Address Book

saved to any other data source, persisted to disk, and/or transferred just as if it were any other file.The key to this functionality is the reliance upon XML, and the disconnected nature of ADO.NET.

Figure 7.1 Object Model for the DataSet

DataSet

Relations

DataRelation

Table Collection

DataTable

Rows

DataRow

Columns

DataColumn

Constraints

PrimaryKey

DataColumn

DefaultView

ChildRelations

DataRelation

ParentRelations

DataRelation

DefaultView

The DataSet requires a DataAdapter to actually interact with a data source.The DataAdapter represents the connection to a data source and the commands used to communicate with the data source to “fill” a DataSet or update a data source. After we are finished adding or updating data in the DataSet, the application would

www.syngress.com

Introduction to ADO.NET: A Simple Address Book • Chapter 7

303

then call the Update method of the DataAdapter to INSERT, UPDATE, and DELETE records as appropriate at the data source.

Note that you don’t have to commit your changes back to the original source; that is, you can transfer data to another data source as long as you have a DataAdapter that understands how to communicate between the DataSet and the final data source.This really serves to emphasize the total and complete disconnected nature of ADO.NET.

The other thing to keep in mind, especially since we are developing for ASP.NET, is that since a DataSet is a disconnected copy of our data, it is most suitable for small amounts of data. For ASP.NET, one would expect to find most of the work of retrieving data to be done using a DataReader, with DataSets being used for relatively static data that must be retrieved often. A DataSet in this scenario could be used at the session level to save some processing at the data source. For example, a Web site might have a drop-down list that contains the 50 states in the United States. If this drop-down list is used more than once on a page, and the number of states is static, we could fill a DataSet and bind every instance of the drop-down list to this DataSet.This way we hit the database once for all 50 states and for all instances of the drop-down list, thus saving many database hits.

The DataReader can be thought of as a firehose Recordset. A firehose Recordset was a nickname given to a read-only, forward-only Recordset in classic ADO. So, a DataReader is a forward-only, non-updateable stream of data from the data provider. Consider this as proof of a DataReader’s speed; a DataAdapter creates a DataReader behind the scenes to populate a DataSet. Because of this simple fact, the DataReader is very useful for ASP.NET work. In a stateless environment such as the Internet, fast access to the data is very important. It may be wasteful to retrieve this data into a DataSet, read through it once to render HTML, and then discard it.The point here is to be aware of the overhead that the DataSet has and use it when it makes sense.

The next item to discuss is the idea of Managed Providers. Managed Providers are namespaces that are written specifically to take advantage of the strengths of a particular data source.The ADO.NET Beta 2 release shipped with two Managed Providers: System.Data.OleDb and System.Data.SqlClient.The idea of Managed Providers is somewhat different from classic ADO where the Provider property dictated the data source you were connecting to. For example, if you were connecting to a Microsoft access database, you would use the Microsoft.Jet.OLEDB.4.0 as the Provider attribute in your connection string. For SQL Server, you would use

www.syngress.com

304 Chapter 7 • Introduction to ADO.NET: A Simple Address Book

“SQLOLEDB.1” as the Provider attribute. Every thing else about the connection object would be the same.

In the case of the System.Data.OleDb namespace, we select the OLEDB provider in much the same way that we selected them in classic ADO.We specify the Provider attribute in the connection string. In the case of the System.Data

.SqlClient namespace, Microsoft has written this namespace to bypass the OLEDB protocol and instead use the Tabular Data Stream (TDS) protocol.The TDS protocol is much more efficient than the OLEDB protocol and allows for much greater speed when working with data.The downside is that the System.Data

.SqlClient namespace can only be used to interact with SQL Server versions 7.0 and up; therefore, we do not need to specify the Provider attribute when using the System.Data.SqlClient namespace.These providers are explained in more detail later in the chapter.

For example, a connection to SQL Server in VB6 would look like this:

Dim oConn as ADODB.Connection

Dim strConn as String

strConn = "Provider=SQLOLEDB.1;Password=chapter7;User ID=Chapter7;Initial _

Catalog=Chapter7;Data Source=localhost

SET oConn = New ADODB.Connection

It becomes this in VB.NET, using the OleDb namespace:

Dim oConn as OleDbConnection

Dim strConn as String

strConn = "Provider=SQLOLEDB.1;Password=chapter7;User ID=Chapter7;Initial _

Catalog=Chapter7;Data Source=localhost

oConn = New OleDbConnection(strConn)

And it becomes this in VB.NET, using the SqlClient namespace:

Dim oConn as SqlConnection

Dim strConn as String

www.syngress.com

Introduction to ADO.NET: A Simple Address Book • Chapter 7

305

strConn = "Password=chapter7;User ID=Chapter7;Initial _ Catalog=Chapter7;Data Source=localhost

oConn = New SqlConnection(strConn)

Notice the difference in the connection strings in the previous examples.The major difference in the OleDb connection string and the SqlClient connection string was the absence of the Provider property in the SqlClient example. If you leave the Provider property in the connection string for an SqlConnection object, ADO.NET throws an exception.We discuss connection strings in great detail later in this chapter.

Supported Connectivity

ADO.NET Beta 2 comes with two namespaces.The System.Data.SqlClient namespace is used with Microsoft SQL Server version 7.0 and up.The System.Data.OleDb namespace is more generic and provides services for MS SQL, MS Access, Oracle, and any other data providers that implement the OLE DB interfaces. Microsoft has tested the System.Data.OleDb namespace with SQL Server, MS Access, and Oracle. If your application will be using SQL Server only, then you can comfortably use the System.Data.SqlClient namespace and take advantage of the tight integration to the Microsoft SQL Server APIs. If, on the other hand, you are not sure, or you know for sure that your application will use a variety of data sources, then you should use the System.Data.OleDb namespace.

With the namespaces explained, we can discuss connectivity.As stated above, ADO.NET is connectionless by nature.That is, we do not open a connection and maintain it.The DataReader is sort of a departure from this in the respect that a DataReader is connected while it is streaming data, but when the DataReader gets to the end of the data, it releases the connection. If you need truly connected scrolling cursors to work with, then you are going to have to go back to classic ADO with the Interop libraries and do things the old-fashioned way. Since we are building a high-performance address book in our example in this chapter, we are not interested in maintaining a connection.We will concentrate on the DataReader object, using the System.Data.SqlClient and the System.Data.OleDb namespaces.

The System.Data Namespace

The System.Data namespace is the foundation for ADO.NET.This namespace contains the classes that form the ADO.NET architecture.The heart of the architecture is the DataSet, which contains a collection of DataTables.We will go into

www.syngress.com

306 Chapter 7 • Introduction to ADO.NET: A Simple Address Book

detail about these objects later in the chapter.The classes in this namespace are data source agnostic; therefore they are independent of the data source and the method used to connect to it.

The System.Data namespace is imported in the Code-Behind files in our samples.This keeps us from having to fully qualify the objects in the class definition. For example, Figure 7.2 (A and B) shows the difference between fully qualifying an object name and using the Imports keyword for VB.NET, and the Using keyword in C#.NET.

Figure 7.2 (A and B) Difference between Fully Qualified Namespace and Using the Imports or Using Keywords

Figure 7.2A Fully Qualified Namespace in C#.NET

// Fully qualified SqlConnection

oConnection = System.Data.SqlClient.SqlConnection(strConn);

// Simplified

using System.Data.SqlClient;

oConnection = SqlConnection(strConn);

Figure 7.2B Fully Qualified Namespace in VB.NET

'Fully qualified SqlConnection

oConnection = System.Data.SqlClient.SqlConnection(strConn)

'Simplified

Imports System.Data.SqlClient

oConnection = SqlConnection(strConn)

Here are some of the common classes in the System.Data namespace:

DataSet

DataTable

DataView

DataColumn

DataException

System.Data namespace contains interfaces that are implemented by .NET data providers.You can find more information on these interfaces in the Visual

www.syngress.com

Introduction to ADO.NET: A Simple Address Book • Chapter 7

307

Studio .NET Documentation, and I urge you to dig into the supplied documentation. Microsoft has put a great deal of effort into the documentation effort.

The System.Data.Common Namespace

The classes in the System.Data.Common namespace are shared throughout the ADO.NET by the various data providers.These classes form the base classes for common objects in the SqlClient and the OleDb namespaces.This namespace contains the general classes for connecting to data sources, filling DataSets, column mapping, and some simple events. I have included it here for completeness; however, you won’t be using it much.The following namespaces play a much bigger role in managing data in ADO.NET.

The System.Data.OleDb Namespace

The System.OleDb namespace provides objects that enable us to connect to OLEDB providers. OLE-DB is an open specification for data providers that allow for flexible access to many Microsoft and third-party data sources.This provides us with one data access technology to connect to and manipulate data in several database products, without having to change libraries.The System.Data.OleDb namespace has been tested by Microsoft to work with Microsoft Access, Microsoft SQL Server, and Oracle. In theory, any data provider that has an OLEDB interface can be used in ADO.NET.

ODBC or, Open Database Connectivity, is part of the OLE-DB specification, but Microsoft did not include it with the Beta 2 release. Microsoft has subsequently released the ODBC namespace for download as a separate installation. Microsoft considers OLE-DB to be the replacement for ODBC, and for the most part it has replaced it. Our example here will use System.Data.OleDb to connect to an Access 2002 version of the Address Book. More information can be found on OLE-DB at www.microsoft.com/data/oledb/.

Some common classes in the System.Data.SqlClient namespace are as follows:

OleDbConnection

OleDbCommand

OleDbDataAdapter

OleDbDataReader

www.syngress.com

308 Chapter 7 • Introduction to ADO.NET: A Simple Address Book

The System.Data.SqlClient Namespace

The System.Data.SqlClient namespace inherits from the System.Data.Common namespace, but uses the TDS protocol that is proprietary to Microsoft SQL Server. Because of the tight integration with SQL Server, developers will only use objects derived from the System.Data.SqlClient namespace to connect to and manipulate data in Microsoft SQL Server.This namespace will connect to Microsoft SQL Server versions 7.0 and higher.We will be using SQL Server 2000 for our example, but you could just as easily use SQL 7.0.

The System.Data.SqlClient classes have the same properties, methods, and events as the System.Data.OleDb class, which makes switching back and forth very easy. Add to this the disconnected nature of the System.Data namespace from which most our data objects are derived, and you get the idea of how easy it is to pull and replace one Managed Provider with another.

Some common classes in the System.Data.SqlClient namespace are as follows:

SqlConnection

SqlCommand

SqlDataAdapter

SqlDataReader

The System.Data.SqlTypes Namespace

The System.Data.SqlTypes namespace contains the classes that map .NET data types to native SQL Server data types.This may sound trivial; however, there are many issues with converting data from one type to another that can cause loss of precision.The classes in the System.Data.SqlTypes provide a safe and more efficient means of handling these conversion issues. Figure 7.3 (A, B, C, and D) is an example of the different uses for the objects in the System.Data.SqlTypes namespace, and the SqlDbType enumeration in the System.Data namespace.

Figure 7.3 (A, B, C, and D) Difference between SqlTypes Namespace and the SqlDbType Enumeration

Figure 7.3A Using SqlTypes in C#.NET

System.Data.SqlTypes.SqlInt32 iAddrsID;

www.syngress.com

Introduction to ADO.NET: A Simple Address Book • Chapter 7

309

Figure 7.3B Using SqlTypes in VB.NET

Dim iAddrsID As System.Data.SqlTypes.SqlInt32

To create a command parameter with a VarChar data type:

Figure 7.3C Creating Command Parameters with C#.NET

oCmd.Parameters.Add("@FName", SqlDbType.VarChar, 50).Value = FName;

Figure 7.3D Creating Command Parameters with VB.NET

oCmd.Parameters.Add("@FName", SqlDbType.VarChar, 50).Value = FName

Do not confuse the SqlDbTypes enumeration in the System.Data namespace with the System.Data.SqlTypes namespace.The SqlDbTypes enumeration is useful for specifying the data type of a parameter that belongs to a Command object.The classes in System.Data.SqlTypes are used for declaring variables.

The SqlDbType and the System.Data.SQLTypes may sound the same, but they are very different in nature and in use. Refer to Table 7.1 for the mapping from native SQL Server data types to the types provided in System.Data.SqlTypes and to the SqlDbTypes enumeration.

Table 7.1 Data Type Mapping

 

 

SqlDbType from

 

Native SQL Server

System.Data.SqlTypes

System.Data

 

 

 

 

 

Bigint

SqlInt64

BigInt

 

Binary

SqlBinary

Binary

 

Bit

SqlBit

Bit

 

Char

SqlString

Char

 

Datetime

SqlDateTime

DateTime

 

Decimal

SqlNumeric

Decimal

 

Float

SqlDouble

Float

 

Image

SqlBinary

Image

 

Int

SqlInt32

Int

 

Money

SqlMoney

Money

 

Nchar

SqlString

NChar

 

Ntext

SqlString

NText

 

 

 

 

 

Continued

www.syngress.com