Professional Documents
Culture Documents
NET
ADO.NET
Overview
Objectives
This module introduces ADO.NET, the evolutionary next step for Microsoft ActiveX Data Objects (ADO). What You Will Learn The difference between ADO and ADO.NET The benefits of ADO.NET ADO.NET core concepts and architecture, including the ADO.NET object model, introduction to the System.Data namespace, the DataSet, and data views; .NET data providers, and more Recommended Reading "ADO+ Guides the Evolution of the Data Species" http://msdn.microsoft.com/library/techart/adoplus.htm Microsoft ADO.NET newsgroup: microsoft.public.dotnet.framework.adonet
ADO.NET
Overview
ADO.NET
Overview
Designed for connected access ADO is based on the concept of a 24/7 (24 hours, 7 days a week) connected world, such as is found on a corporate local area network (LAN). You create a RecordSet; connect it to a data sourcemost often a databaseand work. The RecordSet stays plugged in, if you will, to the data source, and changes to the data are posted to the data store immediately. A model based on connected data can make it difficult and impractical to exchange data across application and organizational boundaries. If two components need to share the same data, both have to be connected, or a way must be devised for the components to pass data back and forth. There are times when it is still useful to work with connected data. For example, in an application that performs a high volume of updates with possible record contention, a connected data architecture can be very important. A typical scenario is a ticket-booking application, where users need to work with information that is up to the moment. For these types of applications, you might wish to design your data access around ADO.
ADO.NET
However, a connected architecture is impractical (if not impossible!) in the disconnected world of the Internet. For an Internet-based solution, you should certainly look at ADO.NET as your data access technology. RecordSet is one table that contains all the data The ADO RecordSet is limited in flexibility and functionality. For example, most useful data analysis or presentation requires views of your data that span multiple tables or data sources. Using ADO, this cannot be accomplished without performing a SQL JOIN. As you may or may not know, this is a performance drag. It consumes memory and CPU power on the database serverprecious resources especially with todays Internet user demands. Because a RecordSet is essentially a single result table, navigation is sequential, row-by-row. Thus, if you perform a joining query the resulting data is flattened; any relations that may have existed are not relationally navigable. Another, perhaps more impressive point is that ADO does not support an abstract data model. It is tied to the physical data source. Data types are bound to COM/COM+ data types A rather significant limitation of ADO is that the available data types are restricted to Component Object Model (COM) and COM+ data types. That means that sometimes you need to fit a square peg in a round hole. For example, in COM/COM+ programming the BSTR is typically used to represent strings that need to be interoperable across languages. For those of you who do not know, the BSTR type is a null-terminated string whose leading WORD contains the length of the string. Unfortunately, the BSTR type is really a stranger to all languages and only makes sense in the COM context. For C, C++, and other lower level languages you must use special COM run-time functions to create and destroy them, and rapid application development (RAD) environments like Microsoft Visual Basic need explicit support in the runtime to handle these types. Data sharing via COM marshalling Sharing data between components in your application or elsewhere is done through COM marshalling. This limits sharing of data to a COM or COM-friendly environment.
ADO.NET
Problems marshalling through firewalls (DCOM, binary) There are also problems with marshalling through firewalls, because they tend to restrict the type of data that can pass through them. COM marshalling requires (COM) system services on the other side of the firewall (the server), but firewalls are often set up to block such traffic because it could pose a security threat.
ADO.NET
Overview
ADO.NET
XML, like HTML, is plaintext: Firewall friendly The use of XML and XML schemata in ADO.NET also makes it possible to share data between DataSets and other components or applicationswithout limitation. Because XML is just plaintext it can more readily pass through firewalls without being burned. The reason is that, unlike binary data (COM/COM+), firewalls can inspect XML data it's just text.
ADO.NET
Overview
Benefits of ADO.NET
We have already touched on the benefits of ADO.NET verses ADO in our comparison. As you learned, XML is used throughout ADO.NET and this has its own benefits. Interoperability through use of XML XML is an open Web standard, is human readable and decipherable text, and is data that describes itself (metadata). This makes it easy to share, interpret, and work with. For these reasons, XML is used to represent and transfer all data in ADO.NET. Scalability through the disconnected DataSet On the scalability side of things, because connections are not maintained for long periods, there is little possibility that database locking will occur. However, by specifically using Service Components you can perform locking. ADO.NET brings the connected world of the Internet to your solutions through its disconnected model. You can now design and implement your applications without the extra consideration toward resource loads on your database-server tier. Simply: Connect, execute one or more queries, and disconnect. Maintainability ADO.NET, like much of .NET, is built around the idea of separation of data logic and user interface. This means you can create your application in independent layers. For example, you can establish a data access layer, a business logic layer, and an interface faade (or user interface). Designing and building your application this way limits collateral damage when you update any given aspect of your solution.
10
ADO.NET
Overview
The typed programming model is also easier to read and comprehend for both programmers and nonprogrammers! To this end, ADO.NET enables you to create typed DataSets in which you define the schema for the DataSet and its data. Microsoft Visual Studio.NET dynamically creates code based on a schema (.xsd) and generates a file (.cs) containing the strongly typed DataSet. Visual Studio.NET uses this for statement completion, as well as compile-time type checking. Wizard Support Visual Studio.NET provides several wizards aimed to make rapid application development possible. These wizards enable you to visually select the tables you wish to work with from your data source, for instance, and then automatically generate the select, insert, update and delete queries for you! The wizards also make creating DataSet objects based on your selection of tables
ADO.NET
11
DataSet
the
There is also an XML Designer that makes it easy to create data schemas. By using the designer in this way you create the DataSet and its corresponding DataTable objects and relations. There is plenty of additional wizard support for ADO.NET in Visual Studio.NET, but that it not the topic of this module.
12
ADO.NET
The core namespaces of ADO.NET that you will work with are System.Data and System.Data.OleDb. The System.Data.Common namespace contains the classes that are common to all .NET data providers. Two other namespaces that are arguably part of ADO.NET are System.Data.SqlClient and System.Data. SQLTypes; these are both optimized for use with Microsoft SQL Server. Combined, these five namespaces provide you with the means to connect to data sources, retrieve information, store it (in an in-memory cache), update your cached data, and post it back to the data sources. You also have the ability to modify the data sources schema from your DataSet. That is, you can create new tables, make new relations, and update the data source with the information.
ADO.NET
13
ADO.NET-related Namespaces
You may think of ADO.NET as a pyramid in which the topmost, main tier is the System.Data namespace. Below that you have the System.Data.Common, System.Data.OleDb, System.Data.SqlClient, and System.Data.SqlClientTypes namespaces.
14
ADO.NET
System.Data Namespace
The ADO.NET object model System.Data namespace. is contained in the
Contains the basis and bulk of ADO.NET As its name implies, System.Data is all about data! For this reason, System.Data is the centerpiece of ADO.NET and the data-centric namespace. Provides the means to work on and with your data! It contains a myriad of classes for working with data Ability to create views of your data Means to logically represent your data Enables the use of XML to view, share, and store data It is the means to work on and with your data!
ADO.NET
15
16
ADO.NET
ADO.NET
17
18
ADO.NET
For example, assume your database has three tables: Customers, Addresses, and CreditCards. You can perform a query on your for customers whose addresses are in a particular region and also retrieve their credit card information. The result of your query would be stored in the DataSet, but the corresponding Customers, Addresses, and CreditCards tables need not exist in the DataSet. On the other hand, you can create tables in the DataSet, called DataTables, and create relations between them. Again, the tables and relations you create in the DataSet need not be bound to those in the data source but may be your own logical representation. Disconnected from the data source The DataSet is an in-memory cache designed to be disconnected from the data source. You simply connect to the data source using an OleDbConnection object (or SqlConnection object), execute your query or queries, and then close the connection. You can then work with the cached data, and when you are ready to update the data source you simply reconnect to the data source and issue an update command. We have already learned some of the advantages of this disconnected philosophy. XML used to read and write data and schema In the .NET Framework, XML plays an important and pervasive role. So, why should ADO.NET be any different? As we have already learned, DataSet objects communicate using XML documents, which means they can communicate with just about anything! You will learn more about the reading and writing XML documents in ADO.NET later. At this time, suffice it to say that the DataSet stores and communicates using XML and XML schemata.
ADO.NET
19
20
ADO.NET
which is especially useful when reading or writing a DataSets XML schema or data Using Properties Sample The following code snippet uses the Tables property of the DataSet myDataSet to add a newly created DataTable to the DataSet.
DataTable newTable = new DataTable( Addresses ); // Creation of the columns and rows of the // Address table is not shown. myDataSet.Tables.Add( myTable);
In the following example, the DataTableCollection of a DataSet is returned so that you may iterate over it to retrieve the DataTables that are contained in the DataSet.
DataTableCollection myDataTableCollection; myDataTableCollection = myDataSet.Tables; // Iterate over the collection... // Iteration not shown.
ADO.NET
21
22
ADO.NET
The DataTable
Maps DataSet data to a physical table in the data source You may create a DataTable object and map it to a data sources table. That is, if your data schema contains a table called Customers you can create a DataTable in the DataSet to correspond to the physical table in a one-toone manner. It is also possible to create DataTable objects that do not correspond to any table in the data source. The choice is yours, depending solely on what makes sense logically to you. Can be related to one another through DataRelations In a physical model of the database or other data schema, tables are often related to one another in different logical ways. For example, a CustID column in one table may have a corresponding column in another table. An example would be a Customers table and an Addresses table (for customers). As a customer may have more than one address, it is logical that a one-to-many correspondence may exist via a common column, such as the customer name or ID. ADO.NET facilitates creating this type of relation between DataTable objects with DataRelation objects. Properties of Interest Columns Gets the columns as a collection. This returns the ColumnsCollection containing any/all DataColumn objects.
ADO.NET
23
Rows Returns the rows of the DataTable. Technically, a RowsCollection of DataRow objects is returned. ParentRelations Gets the parent relations as a RelationsCollection. These are the logical relationships of one table to other tables. Constraints Returns the tables constraints as a ConstraintsCollection. DataSet Returns the DataSet to which the DataTable belongs. PrimaryKey Gets or sets the primary key of the table using an array of DataColumn objects. The contained combined objects comprise the tables primary key.
24
ADO.NET
ADO.NET
25
26
ADO.NET
RelationsCollection used to hold/group DataSets relations As you have learned, DataRelations are retrieved or set using the DataSet objects Relations property or the DataTable objects ParentRelations property. Both properties return a RelationsCollection, which is a collection of all DataRelation objects of a DataSet.
ADO.NET
27
28
ADO.NET
ADO.NET
29
Namespace property: Sets the namespace for serialization Full support for SQL Server-style DiffGrams DiffGrams are an XML means to track changes to a DataSet's data and schema. They provide a before and after picture of things, if you will.
30
ADO.NET
ADO.NET
31
32
ADO.NET
ADO.NET
33
34
ADO.NET
ADO.NET
35
DataViewManager By Example
1. Create a DataViewManager using an existing DataSet. 2. Create a DataView on the Orders table. 3. Set the DataViewSettings on the DataTable Orders in the DataSet myDS to Sort in ascending (ASC) order on the CustID column. 4. Repeat steps 1-3 for the Customer table. 5. Set the data source for the the DataGrid (dataGrid1) to the DataViewManager and then set the data member (i.e. the table) that the DataGrid looks upon (i.e. Table1).
36
ADO.NET
The latter is optimized for SQL Server; it is the SQL Server managed provider. System.Data.OleDb is the ADO.NET managed provider The System.Data.OleDb namespace is the ADO.NET managed provider.
ADO.NET
37
38
ADO.NET
ADO.NET
39
Additional functionality is also available. Functionality and Methods to Perform Transactions OleDbConnection provides a BeginTransaction method that returns an OleDbTransaction object. You then can use the returned object to perform transactional operations:
40
ADO.NET
CommitTransaction: Called to commit (and end) a transaction RollbackTransaction: Called to undo a transaction
OleDbConnection Example This simple code snippet simply demonstrates the creation of an OleDbConnection object, using it to open a connection to the data source and then closing the connection.
ADO.NET
41
42
ADO.NET
ADO.NET
43
44
ADO.NET
OleDbCommand Class
Represents a query to execute on the data source In addition containing the query to execute, the OleDbCommand class provides a few additional items, as you can see from the properties of interest. Properties of Interest ActiveConnection Get or set the data source connection. CommandText Get or set the query (text) command, which may be either an SQL statement or the name of a stored procedure. CommandType Get or set how to interpret the command text. The possible CommandType values are: Text (a SQL text statement), StoredProcedure (the name of a stored procedure), or TableDirect (the table name whose columns are returned). CommandTimeout The seconds until connection timeout. OleDbTransaction Get or set the transaction in which the OleDbCommand is to execute (if any).
ADO.NET
45
OleDbDataReader (1/2)
Forward-only data access Designed only for reading data from a data source, the OleDbDataReader is a simple class providing forwardonly data access. Lightweight programming model Because its functionality is very specific (or limited), it is lightweight. This is especially true if you compare using the OleDbDataReader to using OleDbDataAdapter. A point worth mentioning is that the OleDbDataReader is actually instantiated behind the scenes when you use the OleDbDataAdapter! Instantiated & returned by OleDbCommand.ExecuteReader You cannot actually instantiate the OleDbDataReader directly. As you will see in the sample, you declare the OleDbDataReader and the OleDbCommand.Execute() method will instantiate and return it. Ties up the OleDbCommand until it is finished reading Be aware that the OleDbCommand class cannot process any other requests while it is reading data; it blocks until it has finished.
46
ADO.NET
OleDbDataReader (2/2)
The following are the properties and methods of interest when working with the OleDbDataReader. Properties of Interest FieldCount Returns the number of fields in the result set. RecordsAffected Returns the number of affected records . Methods to retrieve data The OleDbDataReader provides the means to retrieve data from a specific column in the currently indexed row. All the Get() methods are type specific - except for GetValue() and GetValues() - meaning that if the column you wish to retrieve is of String type, use GetString(). There are corresponding Get calls for each data type (GetInt32, GetDecimal, and so on). GetValue() returns an object in its native format which you then must handle appropriately. GetValues() returns the entire row as an array of Objects.
Object [] cols = new Object[10] ; reader.GetValues( cols );
The Read method is used to advance the reader to next record and returns false when no more records exist.
ADO.NET
47
OleDbDataReader Sample
This sample shows you how to create and use an OleDbDataReader.
48
ADO.NET
Summary
Summary
As you have learned, ADO.NET is a powerful successor to ADO, providing you with the same disconnected philosophy as the Web. Its architecture is flexible, allowing you represent your data in any logical way you wish. Furthermore, the ADO.NET use of XML for representing data carries forward the .NET philosophy and ensures that data can be communicated with a wide variety of data sources, objects, and applications.
ADO.NET
49
Duwamish Online
The Duwamish Online store is one of the Enterprise Samples delivered with the Visual Studio.NET product. Duwamish implements a fictitious e-commerce bookstore complete with catalogue, personal profile management, and order handling. The Duwamish Sample is shipping in both a C# and a VisualBasic.NET version. Before we are going to start the walkthrough for the technologies that have been presented in this module, you will first learn how to install the Duwamish sample and how the sample is organized.
50
ADO.NET
ADO.NET
51
52
ADO.NET
ADO.NET
53
Common Components
Duwamish7.Common The Common namespace (and subproject) contains all configuration options that are common to all parts of the system. Also common to the entire system are the definitions for the catalogue (Books, Categories) and the order system (Customer, OrderData) and consequently they are located in this shared project that is being used by all layers. While the data is held in ADO.NET DataSets, this should not be confused with being the actual database layer. The Common namespace provides its own, internal relational view of the Duwamish data thats being mapped to a physical data store by the DataAccess layer (next slide). Duwamish7.SystemFramework The SystemFramework contains all utility classes that are implemented to serve a specific technical purpose but are not immediately related to the business code. All of the code in this project is generally useful and applies to projects beyond the scope of Duwamish. It contains diagnostic utility classes, pre and post condition checking, and dynamic configuration tools.
54
ADO.NET
Duwamish7.DataAccess
Contains all database-related code The DataAccess namespace contains all databaserelated code in Duwamish, providing a central point for maintenance if the underlying data model needs to be optimized or extended. The DataAccess module maps the common definitions for the internal data representation that are defined in the Common.Data namespace to the physical layout of the underlying database. Uses ADO.NET architecture The project builds on the ADO.NET infrastructure and uses the SQL Server managed provider to access the data store. To retrieve and manipulate data, DataAccess uses OleDbDataAdapters bound to the DataSets provided by the Common.Data subsystem. Optimized for performance using stored procedures To optimize performance, the sample uses only a minimal set of ad-hoc SQL commands and relies heavily on stored procedures, which are substantially faster.
ADO.NET
55
Duwamish7.BusinessRules
Implements all business rules The BusinessRules layer serves to implement all logic that is mandated by the system requirements. It validates data, implements calculations, and performs the manipulation of data. All data access performed through DataAccess All modifications that are being made to the underlying data store are performed through the DataAccess layer.
56
ADO.NET
Duwamish7.BusinessFacade
Implements logical business subsystems The BusinessFacade sits on top of the BusinessRules and provides a logical subsystem view. The BusinessFacade provides consistent, separate interfaces to the customer system, the order system, and the product system. While data is read through the DataAccess layer, all manipulation is validated and performed through the BusinessRules.
ADO.NET
57
Duwamish7.Web
Implements the user interface for Web access The Web namespace implements the full user interface for the application. Uses ASP.NET architecture The UI is built on top of ASP.NET using Web Forms, custom Web controls, validation, code behind forms, and many more ASP.NET innovations. All functionality accessed through BusinessFacade Of course, all of the data displayed to the user and all interactions run through the BusinessFacade. This layered model enables reusing the entire back end for a shop with a radically different look and behavior or to expose parts of the application as a Web Service or a Windows Forms application.
58
ADO.NET
ADO.NET
59
60
ADO.NET
We will start exploring the code by opening the file CustomerData.cs in the Common project. The first thing youll notice is that the Duwamish team used cascaded namespaces to organize their code into logical groups. The base namespace for the entire Duwamish sample is Duwamish7, and the subnamespace for this project is Duwamish7.Common.Data. Beneath the namespace declaration youll see the using declarations for all namespaces that are being used and referenced within the CustomerData.cs compilation unit (file). As we scroll down we find that CustomerData.cs defines a single, public class CustomerData that implements a simple wrapper around Customer data. To get a better idea of the code structure, use the key sequence CTRL+M, CTRL+-O, or select Edit/Outlining/Collapse to Definitions. The CustomerData class implements two public methods (constructors) that build a DataTable to hold the customer data and one helper BuildDataTable. Before we get ahead of ourselves, let us first look at data members of the CustomerData class; you can find these at the top of the class declaration. Let us concern ourselves only with a subset to keep things simple:
public const String CUSTOMERS_TABLE = "Customers"; public const String EMAIL_FIELD = "Email"; public const String NAME_FIELD = "Name"; public const String ADDRESS_FIELD = "Address"; //...
It should be obvious from the declaration what the Customers data member is: The name of the table to be created. The others may be less obvious. These are the names of the table columns (the DataColumn names). Now, if we examine the body of either of the CustomerData constructors we will notice a call to the private method BuildDataTable. Scanning down to the BuildDataTable definition, we come to the interesting part. Here we can see that the DataTable is created using the Customers string:
DataTable Table DataTable(CUSTOMERS_TABLE); = new
Next, the DataTables columns collection is retrieved. This is needed in order to add columns to the table.
ColumnsCollection Columns = Table.Columns;
ADO.NET
61
With the ColumnsCollection in hand, each DataColumn is added to the DataTable using the collections Add method. The last line of the method adds the new DataTable to the DataSet:
this.Tables.Add(Table);
The other classes in the Common project are quite similar; we wont explore them here. DataAccess We will start exploring the DataAccess project by opening the file Customers.cs. As we scroll down we find that Customers.cs defines a single, public class Customers that implements a simple, common wrapper around data access for information on Customers. The Customers class is designed to manage Customer information. It performs queries on the data source using a SQLOleDbDataAdapter class and the CustomerData class declared and defined in the CustomerData.cs file. Before we get ahead of ourselves, let us first look at data members of the class and note the declaration of a SQLOleDbDataAdapter object.
protected SQLOleDbDataAdapter m_DSCommand;
This data member is used to issue the queries to the data source and DataSet. Next, look into the Customers constructor. Here you will find the instantiation of the SQLOleDbDataAdapter and, more interesting, the use of TableMappings.
m_DSCommand.TableMappings.Add ( "Table", CustomerData.CUSTOMERS_TABLE );
As the well-commented code conveys, the purpose of this statement is to map the data sources table to a corresponding DataSet: CustomerData. Now look at the UpdateCustomers method responsible for synchronizing the information in the CustomerData with the database Customer table. The first thing we need to note is that the UpdateCustomers method takes one in parameter, Customer, of type CustomerData which we know to be the DataSet. Looking into the method body, we see that the update command must first be created, or in this case, retrieved.
m_DSCommand.UpdateCommand GetUpdateCommand(); =
62
ADO.NET
Next we see that the SQLOleDbDataAdapter calls the Update method to update the records in the data source:
m_DSCommand.Update( Customer, CustomerData.CUSTOMERS_TABLE );
The Update method takes two parameters: the DataSet as the source and the data source table used for the table mappings. The code of course checks for update errors and if none occur, it commits the data changes made to the DataSet:
Customer.AcceptChanges();
Thats it! As you can see, Duwamish lends itself to exploring ADO.NET. Its separation of Common and DataAccess make it easy to explore and learn on your own.
ADO.NET
63
Legal Notices
Unpublished work. 2001 Microsoft Corporation. All rights reserved. Microsoft, ActiveX, Visual Basic, Visual Studio, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.