24
Multithreading and ADO.NET 6

Multithreading and ADO - cscbank.info

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

113

Multithreading and ADO.NET

6

114

A Multithreaded Programming

lthough C# contains many exciting features, one of its most powerful is its built-in support for multithreaded programming. A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread,

and each thread defines a separate path of execution. Thus, multithreading is a specialized form of multitasking.

Multithreaded programming relies on a combination of features defined by the C# language and by classes in the .NET Framework. Because support for multithreading is built into C#, many of the problems associated with multithreading in other languages are minimized or eliminated.

Multithreading Fundamentals There are two distinct types of multitasking: process-based and thread-based. It is important to understand the difference between the two. A process is, in essence, a program that is executing. Thus, process-based multitasking is the feature that allows your computer to run two or more programs concurrently. For example, process-based multitasking allows you to run a word processor at the same time you are using a spreadsheet or browsing the Internet. In process-based multitasking, a program is the smallest unit of code that can be dispatched by the scheduler.

A thread is a dispatchable unit of executable code. The name comes from the concept of a “thread of execution.” In a thread-based multitasking environment, all processes have at least one thread, but they can have more. This means that a single program can perform two or more tasks at once. For instance, a text editor can be formatting text at the same time that it is printing, as long as these two actions are being performed by two separate threads.

The differences between process-based and thread-based multitasking can be summarized like this: Process-based multitasking handles the concurrent execution of programs. Thread- based multitasking deals with the concurrent execution of pieces of the same program.

A thread can be in one of several states. In general terms, it can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which is a temporary halt to its execution. It can later be resumed. A thread can be blocked when waiting for a resource. A thread can be terminated, in which case its execution ends and cannot be resumed.

The .NET Framework defines two types of threads: foreground and background. By default, when you create a thread, it is a foreground thread, but you can change it to a background thread. The only difference between foreground and background threads is that a background thread will be automatically terminated when all foreground threads in its process have stopped.

All processes have at least one thread of execution, which is usually called the main thread because it is the one that is executed when your program begins. Thus, the main thread is the thread that all of the preceding example programs in the book have been using. From the main thread, you can create other threads.

The classes that support multithreaded programming are defined in the System.Threading namespace. Thus, you will usually include this statement at the

dell
Highlight

115

start of any multithreaded program:

using System.Threading;

The Thread Class The multithreading system is built upon the Thread class, which encapsulates a thread of execution. The Thread class is sealed, which means that it cannot be inherited. Thread defines several methods and properties that help manage threads. Throughout this chapter, several of its most commonly used members will be examined.

Creating and Starting a Thread There are a number of ways to create and start a thread. This section describes the basic mechanism. Various options are described later in this chapter.

To create a thread, instantiate an object of type Thread, which is a class defined in

System.Threading. The simplest Thread constructor is shown here:

public Thread(ThreadStart entryPoint)

Here, entryPoint is the name of the method that will be called to begin execution of the thread. ThreadStart is a delegate defined by the .NET Framework as shown here:

public delegate void ThreadStart( )

Thus, your entry point method must have a void return type and take no arguments. Once created, the new thread will not start running until you call its Start( ) method, which is defined by Thread. The Start( ) method has two forms. The one used here is

public void Start( )

Once started, the thread will run until the method specified by entryPoint returns. Thus, when entryPoint returns, the thread automatically stops. If you try to call Start( ) on a thread that has already been started, a ThreadStateException will be thrown. Here is an example that creates a new thread and starts it running:

// Create a thread of execution.

using System;

using System.Threading;

class MyThread {

public int Count;

string thrdName;

public MyThread(string name)

{ Count = 0;

thrdName = name;

}

// Entry point of thread.

public void Run() {

Console.WriteLine(thrdName + " starting.");

do {

Thread.Sleep(5

PART II

116

00);

Console.WriteLine("In " + thrdName + ", Count is " + Count);

Count++;

} while(Count < 10);

Console.WriteLine(thrdName + " terminating.");

}

}

class MultiThread {

static void Main() {

Console.WriteLine("Main thread starting.");

// First, construct a MyThread object.

MyThread mt = new MyThread("Child #1");

// Next, construct a thread from that object.

Thread newThrd = new Thread(mt.Run);

// Finally, start execution of the thread.

newThrd.Start();

do {

Console.Write(".");

Thread.Sleep(100);

} while (mt.Count != 10);

Console.WriteLine("Main thread ending.");

}

}

Let’s look closely at this program. MyThread defines a class that will be used to

create a second thread of execution. Inside its Run( ) method, a loop is established that counts from 0 to 9. Notice the call to Sleep( ), which is a static method defined by Thread. The Sleep( ) method causes the thread from which it is called to suspend execution for the specified period of milliseconds. When a thread suspends, another thread can run. The form used by the program is shown here:

public static void Sleep(int milliseconds)

The number of milliseconds to suspend is specified in milliseconds. If milliseconds is zero, the calling thread is suspended only to allow a waiting thread to execute.

Inside Main( ), a new Thread object is created by the following sequence of statements:

// First, construct a MyThread object.

MyThread mt = new MyThread("Child #1");

// Next, construct a thread from that

object. Thread newThrd = new Thread(mt.Run);

// Finally, start execution of the

thread. newThrd.Start();

As the comments suggest, first an object of MyThread is created. This object is then used to construct a Thread object by passing the mt.Run( ) method as the entry point. Finally, execution of the new thread is started by calling Start( ). This causes mt.Run( )

117

to begin executing in its own thread. After calling Start( ), execution of the main thread returns to Main( ), and it enters Main( )’s do loop. Both threads continue running, sharing the CPU, until their loops finish. The output produced by this program is as follows. (The precise output that you see may vary slightly because of differences in your execution environment, operating system, and task load.)

Main thread

starting. Child #1

starting.

.....In Child #1, Count is 0

.....In Child #1, Count is 1

.....In Child #1, Count is 2

.....In Child #1, Count is 3

.....In Child #1, Count is 4

.....In Child #1, Count is 5

.....In Child #1, Count is 6

.....In Child #1, Count is 7

.....In Child #1, Count is 8

.....In Child #1, Count is 9

Child #1

terminating. Main

thread ending.

Creating Multiple Threads The preceding examples have created only one child thread. However, your program can spawn as many threads as it needs. For example, the following program creates three child threads:

// Create multiple threads of execution.

using System;

using System.Threading;

class MyThread {

public int Count;

public Thread Thrd;

public MyThread(string name) {

Count = 0;

Thrd = new Thread(this.Run);

Thrd.Name = name;

Thrd.Start();

}

// Entry point of thread.

void Run() {

Console.WriteLine(Thrd.Name + " starting.");

do {

Thread.Sleep(500);

Console.WriteLine("In " + Thrd.Name +

", Count is " + Count);

Count++;

} while(Count < 10);

Console.WriteLine(Thrd.Name + " terminating.");

dell
Highlight

118

}

}

class MoreThreads {

static void Main()

{

Console.WriteLine("Main thread starting.");

// Construct three threads.

MyThread mt1 = new MyThread("Child

#1"); MyThread mt2 = new

MyThread("Child #2"); MyThread mt3

= new MyThread("Child #3");

do {

Console.Write

(".");

Thread.Sleep(

100);

} while (mt1.Count < 10 ||

mt2.Count <

10 ||

mt3.Count <

10);

Console.WriteLine("Main thread ending.");

}

}

Sample output from this program is shown next:

Main thread starting.

.Child #1 starting.

Child #2 starting.

Child #3 starting.

....In Child #1, Count is 0

In Child #2, Count is 0

In Child #3, Count is 0

.....In Child #1, Count is 1

In Child #2, Count is 1

In Child #3, Count is 1

.....In Child #1, Count is 2

In Child #2, Count is 2

In Child #3, Count is 2

.....In Child #1, Count is 3

In Child #2, Count is 3

In Child #3, Count is 3

.....In Child #1, Count is 4

In Child #2, Count is 4

In Child #3, Count is 4

.....In Child #1, Count is 5

In Child #2, Count is 5

In Child #3, Count is 5

.....In Child #1, Count is 6

In Child #2, Count is 6

PART II

119

In Child #3, Count is 6

.....In Child #1, Count is 7

In Child #2, Count is 7

In Child #3, Count is 7

.....In Child #1, Count is 8

In Child #2, Count is 8

In Child #3, Count is 8

.....In Child #1, Count is 9

Child #1 terminating.

In Child #2, Count is 9

Child #2 terminating.

In Child #3, Count is 9

Child #3

terminating. Main

thread ending.

As you can see, once started, all three child threads share the CPU. Again, because of differences among system configurations, operating systems, and other environmental factors, when you run the program, the output you see may differ slightly from that shown here.

Determining When a Thread Ends Often it is useful to know when a thread has ended. In the preceding examples, this was attempted by watching the Count variable—hardly a satisfactory or generalizable solution. Fortunately, Thread provides two means by which you can determine whether a thread has ended. First, you can interrogate the read-only IsAlive property for the thread. It is defined like this:

public bool IsAlive { get; }

IsAlive returns true if the thread upon which it is called is still running. It returns false otherwise. To try IsAlive, substitute this version of MoreThreads for the one shown in the preceding program:

// Use IsAlive to wait for threads to

end. class MoreThreads {

static void Main() {

Console.WriteLine("Main thread starting.");

// Construct three threads.

MyThread mt1 = new MyThread("Child #1");

MyThread mt2 = new MyThread("Child #2");

MyThread mt3 = new MyThread("Child #3");

do { Console.Write(".");

Thread.Sleep(100);

} while (mt1.Thrd.IsAlive && mt2.Thrd.IsAlive && mt3.Thrd.IsAlive);

Console.WriteLine("Main thread ending.");

}

}

This version produces the same output as before. The only difference is that it uses IsAlive to wait for the child threads to terminate.

Another way to wait for a thread to finish is to call Join( ). Its simplest form is shown here:

dell
Highlight
dell
Highlight

120

public void Join( )

Join( ) waits until the thread on which it is called terminates. Its name comes from the concept of the calling thread waiting until the specified thread joins it. A ThreadStateException will be thrown if the thread has not been started. Additional forms of Join( ) allow you to specify a maximum amount of time that you want to wait for the specified thread to terminate.

Here is a program that uses Join( ) to ensure that the main thread is the last to stop:

// Use

Join().

using

System;

using System.Threading;

class MyThread {

public int Count;

public Thread Thrd;

public MyThread(string name) {

Count = 0;

Thrd = new Thread(this.Run);

Thrd.Name = name;

Thrd.Start();

}

// Entry point of

thread. void Run() {

Console.WriteLine(Thrd.Name + " starting.");

do {

Thread.Sleep(500

);

Console.WriteLine("In " + Thrd.Name + ", Count is " + Count);

Count++;

} while(Count < 10);

Console.WriteLine(Thrd.Name + " terminating.");

}

}

// Use Join() to wait for

threads to end.

class JoinThreads {

static void Main() {

Console.WriteLine("Main thread starting.");

// Construct three threads.

MyThread mt1 = new MyThread("Child #1");

MyThread mt2 = new MyThread("Child #2");

MyThread mt3 = new MyThread("Child #3");

mt1.Thrd.Join();

PART II

121

Console.WriteLine("Child #1 joined.");

mt2.Thrd.Join();

Console.WriteLine("Child #2 joined.");

mt3.Thrd.Join();

Console.WriteLine("Child #3 joined.");

Console.WriteLine("Main thread ending.");

}

}

Sample output from this program is shown here. Remember when you try the program, your output may vary slightly.

Main thread starting.

Child #1 starting.

Child #2 starting.

Child #3 starting.

In Child #1, Count is 0

In Child #2, Count is 0

In Child #3, Count is 0

In Child #1, Count is 1

In Child #2, Count is 1

In Child #3, Count is 1

In Child #1, Count is 2

In Child #2, Count is 2

In Child #3, Count is 2

In Child #1, Count is 3

In Child #2, Count is 3

In Child #3, Count is 3

In Child #1, Count is 4

In Child #2, Count is 4

In Child #3, Count is 4

In Child #1, Count is 5

In Child #2, Count is 5

In Child #3, Count is 5

In Child #1, Count is 6

In Child #2, Count is 6

In Child #3, Count is 6

In Child #1, Count is 7

In Child #2, Count is 7

In Child #3, Count is 7

In Child #1, Count is 8

In Child #2, Count is 8

In Child #3, Count is 8

In Child #1, Count is 9

Child #1 terminating.

In Child #2, Count is 9

Child #2 terminating.

In Child #3, Count is 9

Child #3 terminating.

Child #1 joined.

Child #2 joined.

Child #3 joined.

Main thread ending.

As you can see, after the calls to Join( ) return, the threads have stopped executing.

122

The IsBackground Property As mentioned earlier, the .NET Framework defines two types of threads: foreground and background. The only difference between the two is that a process won’t end until all of its foreground threads have ended, but background threads are terminated automatically after all foreground threads have stopped. By default, a thread is created as a foreground thread. It can be changed to a background thread by using the IsBackground property defined by Thread, as shown here:

public bool IsBackground { get; set; }

To set a thread to background, simply assign IsBackground a true value. A value of false indicates a foreground thread.

Thread Priorities Each thread has a priority setting associated with it. A thread’s priority determines, in part, how frequently a thread gains access to the CPU. In general, low-priority threads gain access to the CPU less often than high-priority threads. As a result, within a given period of time, a low-priority thread will often receive less CPU time than a high-priority thread.

public ThreadPriority Priority{ get; set; }

ThreadPriority is an enumeration that defines the following five priority settings:

ThreadPriority.Highest ThreadPriority.AboveNormal ThreadPriority.Normal ThreadPriority.BelowNormal ThreadPriority.Lowest

The default priority setting for a thread is ThreadPriority.Normal.

Synchronization When using multiple threads, you will sometimes need to coordinate the activities of two or more of the threads. The process by which this is achieved is called synchronization. The most common reason for using synchronization is when two or more threads need access to a

PART II

dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight

123

shared resource that can be used by only one thread at a time. For example, when one thread is writing to a file, a second thread must be prevented from doing so at the same time. Another situation in which synchronization is needed is when one thread is waiting for an event that is caused by another thread. In this case, there must be some means by which the first thread is held in a suspended state until the event has occurred. Then the waiting thread must resume execution.

The key to synchronization is the concept of a lock, which controls access to a block of code within an object. When an object is locked by one thread, no other thread can gain access to the locked block of code. When the thread releases the lock, the object is available for use by another thread.

The lock feature is built into the C# language. Thus, all objects can be synchronized. Synchronization is supported by the keyword lock. Since synchronization was designed into C# from the start, it is much easier to use than you might first expect. In fact, for many programs, the synchronization of objects is almost transparent.

The general form of lock is shown here:

lock(lockObj) { // statements to be synchronized

} The following program demonstrates synchronization by controlling access to a method

called SumIt( ), which sums the elements of an integer array:

// Use lock to synchronize access to an object.

using System;

using System.Threading;

class SumArray {

int sum;

object lockOn = new object(); // a private object to lock on

public int SumIt(int[] nums) {

dell
Highlight

124

lock(lockOn) { // lock the entire method

sum = 0; // reset sum

for(int i=0; i < nums.Length; i++) {

sum += nums[i];

Console.WriteLine("Running total for " +

Thread.CurrentThread.Name +

" is " + sum);

Thread.Sleep(10); // allow task-switch

}

return sum;

}

}

}

class MyThread {

public Thread Thrd;

int[] a;

int answer;

// Create one SumArray object for all instances of MyThread.

static SumArray sa = new SumArray();

// Construct a new thread.

public MyThread(string name, int[] nums) {

a = nums;

Thrd = new Thread(this.Run);

Thrd.Name = name;

Thrd.Start(); // start the thread

}

// Begin execution of new thread.

void Run() {

Console.WriteLine(Thrd.Name + " starting.");

answer = sa.SumIt(a);

Console.WriteLine("Sum for " + Thrd.Name +

" is " + answer);

Console.WriteLine(Thrd.Name + " terminating.");

}

}

class Sync {

static void Main() {

int[] a = {1, 2, 3, 4, 5};

MyThread mt1 = new MyThread("Child #1", a);

MyThread mt2 = new MyThread("Child #2", a);

mt1.Thrd.Join();

mt2.Thrd.Join();

}

}

PART II

125

Here is sample output from the program. (The actual output you see may vary slightly.)

Child #1 starting.

Running total for Child #1 is 1

Child #2 starting.

Running total for Child #1 is 3

Running total for Child #1 is 6

Running total for Child #1 is 10

Running total for Child #1 is 15

Running total for Child #2 is 1

Sum for Child #1 is 15

Child #1 terminating.

Running total for Child #2 is 3

Running total for Child #2 is 6

Running total for Child #2 is 10

Running total for Child #2 is 15

Sum for Child #2 is 15

Child #2 terminating.

The Monitor Class and lock The C# keyword lock is really just shorthand for using the synchronization features defined by the Monitor class, which is defined in the System.Threading namespace. Monitor defines several methods that control or manage synchronization. For example, to obtain a lock on an object, call Enter( ). To release a lock, call Exit( ). These methods are shown here:

public static void Enter(object syncOb) public static void Exit(object syncOb)

Here, syncOb is the object being synchronized. If the object is not available when Enter( ) is called, the calling thread will wait until it becomes available. You will seldom use Enter( ) or Exit( ), however, because a lock block automatically provides the equivalent. For this reason, lock is the preferred method of obtaining a lock on an object when programming in C#.

One method in Monitor that you may find useful on occasion is TryEnter( ). One of its forms is shown here:

public static bool TryEnter(object syncOb)

It returns true if the calling thread obtains a lock on syncOb and false if it doesn’t. In no case does the calling thread wait. You could use this method to implement an alternative if the desired object is unavailable.

Monitor also defines these three methods: Wait( ), Pulse( ), and PulseAll( ). They are described in the next section.

Terminating a Thread It is sometimes useful to stop a thread prior to its normal conclusion. For example, a debugger may need to stop a thread that has run wild. Once a

PART II

dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight

126

thread has been terminated, it is removed from the system and cannot be restarted.

To terminate a thread prior to its normal ending point, use Thread.Abort( ). Its simplest form is shown here:

public void Abort( )

Abort( ) causes a ThreadAbortException to be thrown to the thread on which Abort( ) is called. This exception causes the thread to terminate. This exception can also be caught by your code (but is automatically rethrown in order to stop the thread). Abort( ) may not always be able to stop a thread immediately, so if it is important that a thread be stopped before your program continues, you will need to follow a call to Abort( ) with a call to Join( ). Also, in rare cases, it is possible that Abort( ) won’t be able to stop a thread. One way this could happen is if a finally block goes into an infinite loop.

The following example shows how to stop a thread by use of Abort( ):

// Stopping a thread by use of Abort().

using System;

using System.Threading;

class MyThread {

public Thread Thrd;

public MyThread(string name) {

Thrd = new Thread(this.Run);

Thrd.Name = name;

Thrd.Start();

}

// This is the entry point

for thread. void Run() {

Console.WriteLine(Thrd.Name + " starting.");

for(int i = 1; i <= 1000; i++) {

Console.Write(i + " ");

if((i%10)==0) {

Console.WriteLine();

Thread.Sleep(250);

}

}

Console.WriteLine(Thrd.Name + " exiting.");

}

}

class StopDemo {

static void Main() {

MyThread mt1 = new MyThread("My Thread");

Thread.Sleep(1000); // let child thread start executing

Console.WriteLine("Stopping thread.");

mt1.Thrd.Abort();

mt1.Thrd.Join(); // wait for thread to terminate

PART II

127

Console.WriteLine("Main thread terminating.");

}

}

The output from this program is shown here:

My Thread starting.

1 2 3 4 5 6 7 8 9 10

11 12 13 14 15 16 17 18 19 20

21 22 23 24 25 26 27 28 29 30

31 32 33 34 35 36 37 38 39 40

Stopping thread.

Main thread terminating.

NOTE Abort( ) should not be used as the normal means of stopping a thread. It is meant for specialized situations. Usually, a thread should end because its entry point method returns.

Determining a Thread’s State The state of a thread can be obtained from the ThreadState property provided by Thread. It is shown here:

public ThreadState ThreadState{ get; }

The state of the thread is returned as a value defined by the ThreadState enumeration. It defines the following values:

ThreadState.Aborted ThreadState.AbortRequested

ThreadState.Background ThreadState.Running

ThreadState.Stopped ThreadState.StopRequested

ThreadState.Suspended ThreadState.SuspendRequested

ThreadState.Unstarted ThreadState.WaitSleepJoin

All but one of these values is self-explanatory. The one that needs some explanation is ThreadState.WaitSleepJoin. A thread enters this state when it is waiting because of a call to Wait( ), Sleep( ), or Join( ).

128

What is ADO.Net?

• The data access classes for the .Net framework

• Designed for highly efficient data access

• Support for XML and disconnected record sets

ADO versus ADO.NET AD O.NET Architecture

Feature ADO ADO.NET

Primary Aim Client/server coupled

Disconnected collection of data from data server

Form of data in memory

Uses RECORDSET object (contains one table)

Uses DATASET object (contains one or more DATATABLE objects)

Disconnected access

Uses CONNECTION object and RECORDSET object with OLEDB

Uses DATASETCOMMAND object with OLEDB

Disconnected access across multi-tiers

Uses COM to marshal RECORDSET

Transfers DATASET object via XML. No data conversions required

XML capabilities

XML aware XML is the native transfer medium for the objects

Firewalls Firewalls block system-level COM marshalling

XML flows through the firewall via HTTP

Code

Coupled to the language used, various implementation

Managed code library – Uses Common Language Runtime, therefore, language agnostic

dell
Highlight
dell
Highlight

129

ADO.NET Architecture

ADO.NET Namespaces

System.Data Core namespace, defines types that represent data

System.Data.Common Types shared between managed providers

System.Data.OleDb Types that allow connection to OLE DB compliant data sources

System.Data.SqlClient Types that are optimized to connect to Microsoft® SQL Server

System.Data.SqlTypes Native data types in Microsoft® SQL Server

dell
Highlight
dell
Highlight
dell
Highlight
dell
Highlight

130

Importing the ADO.NET Namespaces Needed to build a data access application

• For OLE DB:

Imports System.Data Imports System.Data.OleDB

• For SQL Server:

Imports System.Data Imports System.Data.SQLClient Connection object

• Connects to databases.

• Two provider-specific classes

• SqlConnection

• OleDbConnection.

• Connections can be opened in two ways:

• Explicitly by calling the Open method on the connection

• Implicitly when using a DataAdapter.

• Connections handle transactions

//Example: Connection Object using System; using System.Windows.Forms; using System.Data.OleDb; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() {

dell
Highlight
dell
Highlight

131

InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string connetionString = null; OleDbConnection cnn ; connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=yourdatabasename.mdb;"; cnn = new OleDbConnection(connetionString); try { cnn.Open(); MessageBox.Show ("Connection Open ! "); cnn.Close(); } catch (Exception ex) { MessageBox.Show("Can not open connection ! "); } } } } Command Object

• Information submitted to a database as a query via a Connection object

• Two provider-specific classes

• SqlCommand

• OleDbCommand

• Input and output parameters are supported, along with return values as part of the command syntax

• Results are returned in the form of streams. Accessed by:

• DataReader object

• DataSet object via a DataAdapter

dell
Highlight
dell
Highlight

132

DataReader Object

• Provides methods and properties that deliver a forward-only stream of data rows from a data source

• When a DataReader is used, parts of the ADO.NET model are cut out, providing faster and more efficient data access

• Access to data is on a per record basis.

• Forward only

• Read only

• Does support multiple recordsets

//Example : OleDbDataReader using System; using System.Windows.Forms; using System.Data.OleDb; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string connetionString = null; OleDbConnection oledbCnn ; OleDbCommand oledbCmd ; string sql = null; connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Your mdb filename;"; sql = "Your SQL Statement Here like Select * from product";

dell
Highlight

133

oledbCnn = new OleDbConnection(connetionString); try { oledbCnn.Open(); oledbCmd = new OleDbCommand(sql, oledbCnn); OleDbDataReader oledbReader = oledbCmd.ExecuteReader(); while (oledbReader.Read ()) { MessageBox.Show(oledbReader.GetValue(0) + " - " + oledbReader.GetValue(1) + " - " + oledbReader.GetValue(2)); } oledbReader.Close(); oledbCmd.Dispose(); oledbCnn.Close(); } catch (Exception ex) { MessageBox.Show("Can not open connection ! "); } } } } DataAdapter Object

• Provides a set of methods and properties to retrieve and save data between a DataSet and its source data store

• Allows the use of stored procedures

• Connects to the database to fill the DataSet and also update the database

• Pipeline between DataSets and data sources

• Geared towards functionality rather than speed

• Disconnected by design

• Supports select, insert, delete, update commands and methods

Using the DataAdapter SQLDataAdapter sqlDA = new SqlDataAdapter(); sqlDA.SelectCommand = new SqlCommand ("select * from authors“,

dell
Highlight

134

sqlConnection); DataSet sqlDS = new DataSet("authorsTable"); sqlDA.Fill(sqlDS, "authorsTable"); DataSet Object

• Replaces the ADO Recordset

• Represents a cache of data that contains tables, columns, relationships, and constraints, just like a database

• Regardless of where the source data comes from, data can all be placed into DataSet objects

• Tracks changes that are made to the data it holds before updating the source data

• DataSet are also fully XML-featured

• Works with all current models of data storage: flat, relational, and hierarchical

Creating DataSets • Setup SqlConnection

• Setup a SqlDataAdapter

• Create a DataSet

• Call the .Fill() method on the DA

// Example: OleDbDataAdapter & DataSet using System; using System.Data; using System.Data.OleDb; using System.Windows.Forms; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() {

dell
Highlight
dell
Highlight
dell
Highlight

135

InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string connetionString = null; OleDbConnection connection ; OleDbDataAdapter oledbAdapter ; DataSet ds = new DataSet(); string sql = null; int i = 0; connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Your mdb filename;"; sql = "Your SQL Statement Here"; connection = new OleDbConnection(connetionString); try { connection.Open(); oledbAdapter = new OleDbDataAdapter(sql, connection); oledbAdapter.Fill(ds); oledbAdapter.Dispose(); connection.Close(); for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++) { MessageBox.Show (ds.Tables[0].Rows[i].ItemArray[0] + " -- " + ds.Tables[0].Rows[i].ItemArray[1]); } } catch (Exception ex) { MessageBox.Show("Cannot open connection ! "); } } } } DataTables

136

• A DataSet contains one or more DataTables.

• Fields are held within the DataTable.

• And in DataRows, DataColumns.

DataView Object

• Provides methods and properties that enable UI objects such as a DataGrid to

bind to a DataSet

• A view of the data contained in the DataSet

• Only used in conjunction with a DataSet

dell
Highlight