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

Visual CSharp .NET Developer's Handbook (2002) [eng]

.pdf
Скачиваний:
36
Добавлен:
16.08.2013
Размер:
4.94 Mб
Скачать

Figure 11.6: The Tracing tab contains options for logging each ODBC action on a particular DSN.

The trace won't start automatically. You'll need to click Start Tracing Now. The push button caption will change to Stop Tracing Now as soon as tracing starts. Click on the button again to turn tracing off.

Note You might see variations in the content of the Tracing tab based on the version of Windows that you use and the Visual Studio features you install. The version shown is for Windows XP with Visual Studio Analyzer installed. In some cases, you'll see three radio buttons that determine when you'll trace the ODBC calls. The default setting is Don't Trace. You'd select All the Time if you were going to work on debugging a single application. The One-Time Only traces the ODBC calls during the next connection— tracing gets turned off as soon as the connection is broken. This is a good selection to choose when a user calls in with a specific problem. You can monitor the connection during one session and then use that information to help you create a plan for getting rid of the bug.

The only other setting that you'll need to worry about is the Log File Path. ODBC normally places the transaction information in the SQL.LOG file in your root directory. However, you may want to place the logging information on a network drive or use a location hidden from the user. The default location normally works fine during the debugging process.

Note Unless you want to create your own logging DLL, don't change the setting in the Custom Trace DLL field. The DLL listed here, ODBCTRAC.DLL, is responsible for maintaining the transaction log.

An Overview of OLE-DB and ADO

One of the more confusing things about working with ADO is understanding that it's not the lowest rung on the ladder. OLE-DB is the basis for anything you do with ADO; it provides the basis for communication with the database. ADO is simply a nice wrapper around the services that OLE-DB provides. In fact, you can even bypass ADO and go right to OLE-DB if you want to. However, using ADO will help you to develop applications much faster. The following sections will help you understand both OLE-DB and ADO.

Understanding OLE-DB

So, what is OLE-DB? As the name implies, it uses OLE (or more specifically, the component object model—COM) to provide a set of interfaces for data access. Just like any other COM object, you can query, create, and destroy an OLE-DB object. The source of an OLE-DB object is a provider. The .NET Framework includes only a few of OLE-DB providers found in the unmanaged version of the product. More will likely arrive as vendors upgrade their database products. The nice thing about OLE-DB is that the same provider works with any Visual Studio product: Visual C++, Visual Basic, and C#.

OLE-DB also relies on events, just as any COM object would. These events tell you when an update of a table is required to show new entries made by other users or when the table you've requested is ready for viewing. You'll also see events used to signal various database errors and other activities that require polling right now.

Microsoft defines four major categories of OLE-DB user. It's important to understand how you fit into the grand scheme of things. The following list breaks the various groups down and describes how they contribute toward the use of OLE-DB as a whole.

Data Provider A developer who creates an OLE-DB provider using the OLE-DB SDK (Software Development Kit). The provider user interfaces to interact with the database and events to signal special occurrences.

Data Consumer An application, system driver, or user that requires access to the information contained in a database.

Data Service Provider A developer who creates stand-alone utilities (services) that enhance the user's or administrator's ability to use or manage the contents of a database. For example, a developer could create a query engine that allows the user to make natural language requests for information in the database. A service works with the OLE-DB provider and becomes an integral part of it.

Business Component Developer A developer who creates application modules or components that reduce the amount of coding used to create a database application. A component could be something as generic as a grid control that allows you to display a subset of the records in the database at a glance or something specific to the type of database being accessed.

Microsoft designed OLE-DB as an upgrade to ODBC. The fact is that many people still use ODBC because they perceive it as easier to use than OLE-DB or ADO. Note that this view is so pervasive that Microsoft finally created ODBC.NET for those developers who refuse to make the change. In addition, more database vendors provide ODBC access (although this is changing now). So, how does OLE-DB differ from ODBC? Table 11.1 shows the major differences between the two products. We'll discuss how these differences affect your usage decisions later in this chapter.

 

Table 11.1: OLE-DB to ODBC Technology Comparison

 

 

 

 

 

 

 

 

Element

 

 

OLE-DB

 

ODBC

 

Comments

 

 

 

 

 

 

 

 

Access type

 

 

Component

 

Direct

 

OLE-DB provides interfaces that

 

 

 

 

 

 

 

 

Table 11.1: OLE-DB to ODBC Technology Comparison

Element

 

OLE-DB

 

ODBC

 

Comments

 

 

 

 

 

 

 

 

 

 

 

 

 

interact with the data. User access

 

 

 

 

 

 

to the data is through components

 

 

 

 

 

 

designed to interact with OLE-DB.

 

 

 

 

 

 

 

Data access

 

Any tabular data

 

SQL

 

Microsoft designed ODBC to use

specialization

 

 

 

 

 

SQL as the basis for data

 

 

 

 

 

 

transactions. In some cases, that

 

 

 

 

 

 

means the programmer has to make

 

 

 

 

 

 

concessions to force the data to fit

 

 

 

 

 

 

into the SQL standard.

 

 

 

 

 

 

 

Driver access method

 

Component

 

Native

 

As mentioned earlier, all access to

 

 

 

 

 

 

an OLE-DB provider is through

 

 

 

 

 

 

COM interfaces using components

 

 

 

 

 

 

of various types. ODBC normally

 

 

 

 

 

 

requires direct programming of

 

 

 

 

 

 

some type and relies heavily on the

 

 

 

 

 

 

level of SQL compatibility

 

 

 

 

 

 

enforced by the database vendor.

 

 

 

 

 

 

 

Programming model

 

COM

 

C/C++

 

OLE-DB relies on COM to provide

 

 

 

 

 

 

the programmer with access to the

 

 

 

 

 

 

provider. This means that OLE-DB

 

 

 

 

 

 

is language independent, while

 

 

 

 

 

 

ODBC is language specific.

 

 

 

 

 

 

 

Technology standard

 

COM

 

SQL

 

OLE-DB adheres to Microsoft's

 

 

 

 

 

 

COM standard, which means that

 

 

 

 

 

 

it's much more vendorand

 

 

 

 

 

 

platform-specific than the SQL

 

 

 

 

 

 

technology standard used by

 

 

 

 

 

 

ODBC.

Don't get the idea that OLE-DB and ODBC are two completely separate technologies meant to replace each other. Microsoft provides an ODBC OLE-DB provider that enables you to access all of the functionality that ODBC provides through OLE-DB or ADO. In other words, the two technologies complement each other and don't act as complete replacements for each other. (Unfortunately, this cross compatibility doesn't translate well to the .NET Framework where OLE-DB and ODBC are separate entities.)

Can you replace ODBC with ADO or OLE-DB? Yes, but you won't get the very best performance from your applications if you do. The whole idea of OLE-DB is to broaden the range of database types that you can access with your C# applications. Obviously, if you do need to access both ODBC and tabular data with a single application, OLE-DB provides one of the better solutions for doing so.

Understanding ADO

Now that you have a little better handle on OLE-DB, where does ADO fit in? As previously mentioned, ADO provides an easy method for accessing the functionality of an OLE-DB

provider. In other words, ADO helps you to create applications quickly and enables C# to take care of some of the details that you'd normally have to consider when using OLE-DB directly. ADO is a wrapper for OLE-DB and reduces the number of steps required to perform common tasks.

ADO represents a new way to provide database access through the combination of databound ActiveX controls and five specialty classes. You can divide the classes into two functional areas: data provider and dataset.

The data provider contains classes that provide connection, command, data reader, and data adapter support. The connection provides the conduit for database communications. The command enables the client to request information from the database server. It also enables the client to perform updates and other tasks. The data reader is a one-way, read-only, disconnected method of viewing data. The data adapter provides the real-time connection support normally associated with live data connections.

The dataset is the representation of information within the database. It contains two collections: DataTableCollection and DataRelationCollection. The DataTableCollection contains the columns and rows of the table, along with any constraints imposed on that information. The DataRelationCollection contains the relational information used to create the dataset.

ADO provides several advantages over previous database access methods. The following list will describe them for you.

Independently Created Objects You no longer have to thread your way through a hierarchy of objects. This feature permits you to create only the objects you need, reducing memory requirements and enhancing application speed.

Batch Updating Instead of sending one change to the server, you can collect them in local memory and send all of them to the server at once. Using this feature improves application performance (because the data provider can perform the update in the background) and reduces network load.

Stored Procedures These procedures reside on the server as part of the database manager. You'll use them to perform specific tasks on the dataset. ADO uses stored procedures with in/out parameters and a return value.

Multiple Cursor Types Essentially, cursors point to the data you're currently working with. You can use both client-side and server-side cursors.

Returned Row Limits You only get the amount of data you actually need to meet a user request.

Multiple Recordset Objects Helps you to work with multiple recordsets returned by stored procedures or batch processing.

Free-Threaded Objects This feature enhances web server performance.

There are two databinding models used for ActiveX controls. The first, simple databinding provides the means for an ActiveX control like a text box to display a single field of a single record. The second, complex databinding enables an ActiveX control like a grid to display multiple fields and records at the same time. Complex databinding also requires the ActiveX control to manage which records and fields the control will display. C# comes with several ActiveX controls that support ADO, including the following:

DataGrid

DataCombo

DataList

Hierarchical Flex Grid

Date and Time Picker

Like OLE-DB, Microsoft based ADO on COM. ADO provides a dual interface: a program ID of ADODB for local operations and a program ID of ADOR for remote operations. The ADO library itself is free-threaded, even though the registry shows it as using the apartmentthreaded model. The thread safety of ADO depends on the OLE-DB provider that you use. In other words, if you're using Microsoft's ODBC OLE-DB provider, you won't have any problems. If you're using a third-party OLE-DB provider, you'll want to check the vendor documentation before assuming that ADO is thread safe (a requirement for using ADO over an Internet or intranet connection).

You'll use seven different objects to work with ADO. Table 11.2 lists these objects and describes how you'll use them. Most of these object types are replicated in the other technologies that Microsoft has introduced, although the level of ADO object functionality is much greater than that offered by previous technologies.

 

 

Table 11.2: ADO Object Overview

 

 

 

Object

 

Description

 

 

 

Command

 

A command object performs a task using a connection or recordset

 

 

object. Even though you can execute commands as part of the

 

 

connection or recordset objects, the command object is much more

 

 

flexible and allows you to define output parameters.

 

 

 

Connection

 

Defines the connection with the OLE-DB provider. You can use this

 

 

object to perform tasks like beginning, committing, and rolling back

 

 

transactions. There are also methods for opening or closing the

 

 

connection and for executing commands.

 

 

 

Error

 

ADO creates an error object as part of the connection object. It provides

 

 

additional information about errors raised by the OLE-DB provider. A

 

 

single error object can contain information about more than one error.

 

 

Each object is associated with a specific event, like committing a

 

 

transaction.

 

 

 

Field

 

A field object contains a single column of data contained in a recordset

 

 

object. In other words, a field could be looked at as a single column in a

 

 

table and contain one type of data for all of the records associated with

 

 

a recordset.

 

 

 

Parameter

 

Defines a single parameter for a command object. A parameter

 

 

modifies the result of a stored procedure or query. Parameter objects

 

 

 

 

 

Table 11.2: ADO Object Overview

 

 

 

Object

 

Description

 

 

 

 

 

can provide input, output, or both.

 

 

 

Property

 

Some OLE-DB providers will need to extend the standard ADO object.

 

 

Property objects represent one way to perform this task. A property

 

 

object contains attribute, name, type, and value information.

 

 

 

Recordset

 

Contains the result of a query and a cursor for choosing individual

 

 

elements within the returned table. C# gives you the option of creating

 

 

both a connection and a recordset using a single recordset object or

 

 

using an existing connection object to support multiple recordset

 

 

objects.

 

 

 

Writing an OLE-DB Application

The OLE-DB example will rely on a contact database that contains name and address information for the customers in a company. You'll find the database in the \Chapter 11\DSN folder as MyData.MDB. The example code appears in the \Chapter 11\OLEDB folder on the CD. The following sections show you how to create and code an application that provides both grid and detail views.

Note The examples in this chapter rely on a Microsoft Access database for input. I chose this product because many people ask for Access-specific examples on the various Visual Studio newsgroups and because I've received e-mails asking for this type of example. The examples in Chapters 12 and 13 will rely on SQL Server 2000. The combination of the two database sources should provide you with a better view of how well .NET works for a variety of database application needs. Please feel free to contact me at JMueller@mwt.net with comments.

Creating the Grid View

This example requires more setup than examples in previous chapters. You have to create a connection to the database, provide commands for manipulating the database, use a data adapter to create a place to store the data, and finally, generate a dataset to store the results of the data query. As you'll learn, the Server Explorer in the Visual Studio IDE helps make application creation faster and easier. The following steps show how to use Server Explorer to set up your application.

1.Open the Server Explorer toolbar shown in Figure 11.7 by clicking on the top (rather than the bottom) of the toolbar area on the left side of the Visual Studio IDE. As you can see, this display provides immediate access to local machine resources and data connections. You can also create connections to remote machines.

Figure 11.7: The Server Explorer enables you to create new connections or use existing resources.

2.Right-click Data Connections and choose Add Connection from the context menu. You'll see the Data Link Properties dialog box shown in Figure 11.8. Note that you might have to manually select the Provider tab. Selecting the right provider is an essential part of the application configuration process.

Figure 11.8: Visual Studio .NET includes the list of providers shown in this figure.

3.Select the Microsoft Jet 4.0 OLE-DB Provider option, and then click Next. You'll see a Connection tab that includes the name of the database and logon credentials.

4.Select the database you want to use (the example uses the MyData.MDB file), and then click Test Connection. It's essential to perform the connection test to ensure errors you see in the application aren't due to a lack of access. You should see a Test Connection Succeeded message. If not, try to create the connection again.

Note The Advanced tab contains options that may increase your chances of accessing a database, especially a remote resource. This tab contains options for selecting an impersonation level, protection level, connection timeout, and type of access. The connection timeout value is especially important for Internet resources, because the default timeout assumes a LAN connection. Likewise, the wizard assumes you want to create a Share Deny None connection when you really need a Share Exclusive connection for the application.

5.Click OK to create the connection. The Visual Studio IDE may pause for a few seconds, at this point, to establish the connection. When the IDE establishes the connection, you'll see a new connection in the Server Explorer. An Access database typically provides tables, views, and stored procedures, but you might see other entries within the connection.

6.Locate the Address table in the Tables folder. Drag the Address table to the form. Visual Studio will automatically generate a connection and data adapter for you. Make absolutely certain the data adapter contains entries for the DeleteCommand,

InsertCommand, SelectCommand, and UpdateCommand properties or the example won't work properly. You'll want to rename the connection and data adapter—the example uses AddressConnection and AddressDA.

7.Right-click AddressDA and choose Generate Dataset from the context menu. You'll see a Generate Dataset dialog box.

8.Type AddressDataset in the New field, then click OK. Visual Studio .NET will automatically generate the dataset for you.

The example application uses a menu driven system and includes a toolbar for quick access to commands. It relies on a DataGrid control to display the data. One of the DataGrid configuration tasks is to ensure the DataSource property points to foDataSet1 and the DataMember property points to the FoodOrders query. Check the project on the CD for the remaining configuration items.

Tip The toolbar uses standard icons for the Print and Print Preview menu options (among others). You can find a list of standard icons in the \Program Files\Microsoft Visual Studio .NET\Common7\Graphics\bitmaps\OffCtlBr\Small\Color folder of your Visual Studio installation. Add these icons to an ImageList control, which you can then access within the ToolBar control as a source of images. The example also uses arrows from the \Program Files\Microsoft Visual Studio .NET\Common7\Graphics\icons\arrows folder and modified versions of the arrows found in the \Chapter 11\Graphics folder for record movement icons.

You'll want to pay special attention to the DataGrid configuration because some elements aren't obvious. Look at the TableStyles property and you'll notice that it's a collection not a single value. Click the ellipses button next to the property and you'll see a DataGridTableStyle Collection Editor dialog, similar to the one shown in Figure 11.9. Notice

that this dialog already has an entry in it. You need one entry for each table or query that you want to add to the data grid.

Figure 11.9: The DataGridTable-Style Collection Editor enables you to configure a table for display.

Tip Any modifications you make to the DataGridTableStyle Collection Editor or DataGridColumnStyle Collection Editor dialog box entries will appear in bold type. The use of bold text makes it easy to find any changes you've made.

As you can see, the properties in this dialog box help you set table attributes, such as the default column width and the cell selection color. To make these settings work, you must set the MappingName property to the table or query that you want to configure for display. You also need to configure the GridColumnStyles property, which is another collection. Click the ellipses button and you'll see a DataGridColumnStyle Collection Editor dialog box, like the one shown in Figure 11.10. This figure also shows the columns required for the example application.

Figure 11.10: Configuring the table also implies that you'll configure the associated columns.

Figure 11.10 shows a typical DataGridColumnStyle object entry. You must provide a MappingName property value. In this case, the MappingName refers to a single column

within the table or query. Generally, you'll find that you need to provide values for the HeaderText, NullText, and Width properties. The Format property is a special entry that you'll want to use for special value types such as dates and currency. Because the DataGridColumnStyle object entry in Figure 11.10 is for a date value, the Format property contains an uppercase D for a long date format. You'd use a lowercase d for a short date format. The .NET Framework provides a wealth of format string values that you can learn about in the Formatting Types (mshelp://MS.VSCC/MS.MSDNVS/cpguide/html/cpconformattingtypes.htm) help topic.

Coding the Grid View

Coding database applications can become quite complex depending on the number of tables and application features you want to provide. However, there are certain coding tasks that every Grid view application will have. The first requirement is some means of filling the grid with data. You'll find the following line of code in the GridView class constructor.

AddressDA.Fill(addressDataset1);

This line of code tells the data adapter to fill the data set with data. The connection to the data grid is automatic because of the DataSource and DataMember property entries. The various MappingName entries ensure the data appears in the correct order and in the correct format.

While the connection between the dataset and the data grid is automatic, the connection between the dataset and the data adapter isn't. Changing a value in the data grid doesn't guarantee that it will appear in the database as well. In fact, there are a number of conditions that will prevent the data from ever appearing in the database. For example, you can configure the dataset as read-only, which would prevent changes at a basic level. However, for any change to take place, you must detect the change using the CurrentCellChanged() event and then update the data adapter with the new data. Listing 11.1 shows the code you'll need to perform data grid updates.

Listing 11.1: Updating the Data Adapter

private void AddrDataGrid_CurrentCellChanged(object sender, System.EventArgs e)

{

DialogResult DR; // Used to store the result of a dialog.

try

{

// Update the record to reflect user changes. AddressDA.Update(addressDataset1);

}

catch (DBConcurrencyException DBCE)

{

//If an error occurs, see if the user wants

//to exit the application.

DR = MessageBox.Show("Concurrency Error\r\n" +

DBCE.Message + "\r\n" +

DBCE.Source + "\r\n" +

DBCE.Row + "\r\n" +

"Exit Application?",

"Database Update Error",

MessageBoxButtons.YesNo,