implementing a generic data access layer in ado.net

25
Implementing a in ADO.NET Pa 06. May, 2010 0 Comments A Data Access Layer (DAL) is a of articles that discuss how we constraints in the sense that they independent. This series of articl independent Data Access Layer proper understanding of ADO.N examples in this article in C#. H well. The Strategies Involved in C Let us first understand what the discussing how an application d performs the CRUD (Create, Rea First, you need to open the conn anyway? A provider is respons reason is that a provider for an database and vice-versa. Next, database commands of your cho or a DataTable instance to retr database table. When you use a D database and the DataSet instanc Implementing the DAL Fra With this in mind, let us desi understand the ADO.NET Librar Connection Command Data Reader Data Adapter The corresponding interfaces tha IDBConnection IDataReader IDBCommand a Generic Data Access L art 1 s by admin an integral part in the design of any application. e an implement a DAL using ADO.NET. Mo y are not generic in nature. In other words, they les will discuss the implementation of a generic in ADO.NET. The basic prerequisite to learnin NET and good coding skills in C#. I will p However with little effort, you can twist it ove Creating a Data Access Layer necessities are for building such a layer. I wou designed using ADO.NET actually connects to ad, Update and Delete) operations. nection using a database provider. Fine, but w sible for connecting to a specific database. Wh n Oracle database cannot be used to connect t you need a command object that can be use oice. This is followed by the usage of a DataRea rieve data (if you are performing a Read ope DataSet, you need a DataAdapter as a bridge be ce. amework ign a provider independent Data Access Lay ry. The major classes that constitute the ADO.N at the above classes implement are stated below. Layer There are plenty ost of these have y are not provider c, i.e., a provider ng this article is a present the code er to VB.NET as uld rather start by the database and what is a provider hy specific? The to a SQL Server ed to execute the ader or a DataSet eration) from the etween the actual yer. Let us first NET library are:

Upload: santosh-sutar

Post on 02-Apr-2015

1.159 views

Category:

Documents


47 download

TRANSCRIPT

Page 1: Implementing a Generic Data Access Layer in ADO.NET

Implementing a Generic Data Access Layer

in ADO.NET Part 1

06. May, 2010 0 Comments

A Data Access Layer (DAL) is an integral part in the design of any application. There are plenty

of articles that discuss how we an implement a

constraints in the sense that they are not generic in nature. In other words, they are not provider

independent. This series of articles will discuss the implementation of a generic, i.e., a provider

independent Data Access Layer in ADO.NET. The basic prerequisite to learning this article is a

proper understanding of ADO.NET and good coding skills in C#. I will present the code

examples in this article in C#. However with little effort, you can twist it over to VB.NET a

well.

The Strategies Involved in Creating a Data Access Layer

Let us first understand what the necessities are for building such a layer. I would rather start by

discussing how an application designed using ADO.NET actually connects to the database and

performs the CRUD (Create, Read, Update and Delete) operations.

First, you need to open the connection using a database provider. Fine, but what is a provider

anyway? A provider is responsible for connecting to a specific database. Why specific? The

reason is that a provider for an Oracle database cannot be used to connect to a SQL Server

database and vice-versa. Next, you need a command object that can be used to execute the

database commands of your choice. This is followed by the usage of a DataReader or

or a DataTable instance to retrieve data (if you are performing a Read operation) from the

database table. When you use a DataSet, you need a DataAdapter as a bridge between the actual

database and the DataSet instance.

Implementing the DAL Frame

With this in mind, let us design a provider independent Data Access Layer. Let us first

understand the ADO.NET Library. The major classes that constitute the ADO.NET library are:

• Connection

• Command

• Data Reader

• Data Adapter

The corresponding interfaces that the above classes implement are stated below.

• IDBConnection

• IDataReader

• IDBCommand

Implementing a Generic Data Access Layer

in ADO.NET Part 1

0 Comments by admin

A Data Access Layer (DAL) is an integral part in the design of any application. There are plenty

of articles that discuss how we an implement a DAL using ADO.NET. Most of these have

constraints in the sense that they are not generic in nature. In other words, they are not provider

independent. This series of articles will discuss the implementation of a generic, i.e., a provider

ccess Layer in ADO.NET. The basic prerequisite to learning this article is a

proper understanding of ADO.NET and good coding skills in C#. I will present the code

examples in this article in C#. However with little effort, you can twist it over to VB.NET a

The Strategies Involved in Creating a Data Access Layer

Let us first understand what the necessities are for building such a layer. I would rather start by

discussing how an application designed using ADO.NET actually connects to the database and

erforms the CRUD (Create, Read, Update and Delete) operations.

First, you need to open the connection using a database provider. Fine, but what is a provider

anyway? A provider is responsible for connecting to a specific database. Why specific? The

is that a provider for an Oracle database cannot be used to connect to a SQL Server

versa. Next, you need a command object that can be used to execute the

database commands of your choice. This is followed by the usage of a DataReader or

or a DataTable instance to retrieve data (if you are performing a Read operation) from the

database table. When you use a DataSet, you need a DataAdapter as a bridge between the actual

database and the DataSet instance.

Implementing the DAL Framework

With this in mind, let us design a provider independent Data Access Layer. Let us first

understand the ADO.NET Library. The major classes that constitute the ADO.NET library are:

that the above classes implement are stated below.

Implementing a Generic Data Access Layer

A Data Access Layer (DAL) is an integral part in the design of any application. There are plenty

DAL using ADO.NET. Most of these have

constraints in the sense that they are not generic in nature. In other words, they are not provider

independent. This series of articles will discuss the implementation of a generic, i.e., a provider

ccess Layer in ADO.NET. The basic prerequisite to learning this article is a

proper understanding of ADO.NET and good coding skills in C#. I will present the code

examples in this article in C#. However with little effort, you can twist it over to VB.NET as

Let us first understand what the necessities are for building such a layer. I would rather start by

discussing how an application designed using ADO.NET actually connects to the database and

First, you need to open the connection using a database provider. Fine, but what is a provider

anyway? A provider is responsible for connecting to a specific database. Why specific? The

is that a provider for an Oracle database cannot be used to connect to a SQL Server

versa. Next, you need a command object that can be used to execute the

database commands of your choice. This is followed by the usage of a DataReader or a DataSet

or a DataTable instance to retrieve data (if you are performing a Read operation) from the

database table. When you use a DataSet, you need a DataAdapter as a bridge between the actual

With this in mind, let us design a provider independent Data Access Layer. Let us first

understand the ADO.NET Library. The major classes that constitute the ADO.NET library are:

Page 2: Implementing a Generic Data Access Layer in ADO.NET

• IDBDataAdapter

The Data Providers that make up the library are specific to a particular database that they would

connect to. These are the Data Providers that are available in ADO.NET.

• SQL Server Data Provider

• Oracle Data Provider

• ODBC Data Provider

• OleDB Data Provider

Now we are all set to implement our DAL. The major components that constitute our DAL block

are:

• ProviderType (Enum)

• DatabaseConnectionState (Enum)

• StoredProcedureParameterDirection (Enum)

• DBManager (Class)

• DBHelper (Class)

We will start our discussion with the enum data type that would contain the data provider types

in it. These provider types relate to the databases that we will be connecting to, depending our

requirements. The following code snippet illustrates the ProviderType enum that contains four

values that correspond to a specific data provider.

public enum ProviderType { SqlServer, OleDb, Oracle, ODBC, ConfigDefined }

Now, there may be situations where you might need to either keep the database connection state

open or close after a database operation is over. As an example, after you read data into a

DataReader instance from the underlying database, you might need to keep the connection state

open for subsequent operations. You may also need to close it if it is no longer used. Keeping

this in mind, let us have an enum data type that houses two values that correspond to the

database connection states that we just discussed about. The following is the code for the enum

called DatabaseConnectionState.

public enum DatabaseConnectionState { KeepOpen, CloseOnExit }

When you are executing the stored procedures, you might want to send data to the database or

retrieve the same from the database. Accordingly, we have another enum called

StoredProcedureParameterDirection that contains values that correspond to the parameter

directions for the stored procedures that we would execute with the help of our DAL. The

following is the code for this enum.

public enum StoredProcedureParameterDirection

{ Input, InputOutput, Output, ReturnValue }

We need a factory class that would return a DbProviderFactory type instance or a

DbDataAdapter type instance depending on the data provider that we are using. This class

Page 3: Implementing a Generic Data Access Layer in ADO.NET

contains factory methods that typically are static methods. What is a static method, anyway? This

is an often misunderstood concept but a very important one. Well, a static method, often called a

shared method (it is shared by all instances of the class that it belongs to) belongs to the class and

a non-static method belongs to an object of a class. That is, a non-static method can only be

called on an object of a class that it belongs to. A static method can however be called both on

the class as well as an object of the class. Further, a static method can access the static members

of a class only unlike a non-static method that can access both static and non-static members.

These static methods in the DBFactory class accept a reference to the ProviderType enum that

denotes the data provider type in use.

The next class in our discussion is the DBFactory class, designed on the factory design pattern.

Before we discuss the DBFactory class and its intent, let us understand what a factory design

pattern is. What is a factory design pattern? The Factory pattern is responsible for providing an

interface for the creation of objects, but allows the inherited classes to decide on the appropriate

time of these instantiations.

The following is the source code for our DBFactory class. It contains two static methods called

GetProvider and GetDataAdapter both of which accept an instance of the database provider type

enum, i.e., ProviderType.

using System.Data.Common;

using System.Data.SqlClient;

using System.Data.OleDb;

using System.Data.Odbc;

using System.Data.OracleClient;

using System.Collections.Generic;

using System.Text;

namespace DataAccessLayer

{

internal class DBFactory

{

private static DbProviderFactory objFactory = null;

public static DbProviderFactory GetProvider(ProviderType provider)

{

switch (provider)

{

case ProviderType.SqlServer:

objFactory = SqlClientFactory.Instance;

break;

case ProviderType.OleDb:

objFactory = OleDbFactory.Instance;

break;

case ProviderType.Oracle:

objFactory = OracleClientFactory.Instance;

break;

case ProviderType.ODBC:

objFactory = OdbcFactory.Instance;

break;

}

return objFactory;

}

Page 4: Implementing a Generic Data Access Layer in ADO.NET

public static DbDataAdapter GetDataAdapter(ProviderType providerType)

{

switch (providerType)

{

case ProviderType.SqlServer:

return new SqlDataAdapter();

case ProviderType.OleDb:

return new OleDbDataAdapter();

case ProviderType.ODBC:

return new OdbcDataAdapter();

case ProviderType.Oracle:

return new OracleDataAdapter();

default:

return null;

}

}

}

}

Note that you have different providers for different databases, i.e., the database providers are all

database specific. A DataAdapter as we may recall, is a bridge between the database and the

DataSet – a set of disconnected data. Though you have various data readers depending on the

type of the data provider you are using, you have only one type of data set. Why? This is because

a data set is a disconnected in-memory set of data. The schema of the database defines the

schema of the data set.

Refer to the code example shown above. Both the methods in the code example shown above

check the value of the enum reference instance and accordingly return an appropriate

DbDataProvider or DbProviderFactory instance respectively. Such methods are actually called

factory methods.

Conclusion

In this article we have discussed how we can design and implement and generic data access

layer, i.e., one that can be used to perform database operations irrespective of the database being

used. In the next article in this series, we will discuss the Databasehelper class, i.e., the class that

actually performs the database operations.

Page 5: Implementing a Generic Data Access Layer in ADO.NET

Part 2 08. May, 2010

In the first part of this series of articles on Data Access Layer, we have had a look at what the

strategies are, for designing and implementing a Generic Data Access Layer. We have had a look

at the enumerators and the factory classes that we will be using. In this part of this article of three

part series, we will discuss how we can implement the DatabaseHelper class, one th

responsible for performing the actual database operations.

The DatabaseHelper class encapsulates the various calls to the database to perform the CRUD

operations. The DBManager class that we will discuss later acts as a wrapper on top of this

You have various methods in the DatabaseHelper class to add parameters, to execute queries,

stored procedures, etc.

Here is the code that illustrates how the connection to the database is established based on the

provider type chosen and the command

public DatabaseHelper(string connectionstring, ProviderType provider)

{

this.strConnectionString = connectionstring;

objFactory = DBFactory.GetProvider(provider);

objConnection = objFactory.CreateConnection();

objCommand = objFactory.CreateCommand();

objConnection.ConnectionString = this.strConnectionString;

objCommand.Connection = objConnection;

}

In ADO.NET, you have the following data providers.

• SQL Server Data Provider

• Oracle Data Provider

• Odbc Data Provider

• OleDB Data Provider

Note: Depending on the data provider used, you need to use the command object that is specific

to that provider. Your data reader should also be specific to the data provider used. The use of

the DBFactory class as shown in the code snippet above. Note that you use the command objects

to execute the database commands that contain the SQL statements. Added to this, we will have

overloaded versions of AddParameter method to add parameters to the command objects so that

we can pass parameters to the database stored procedures or SQL statements. Here is the

simplest version of the AddParameter method.

internal int AddParameter(string name, object value)

{

DbParameter dbParameter = objFactory.CreateParameter();

dbParameter.ParameterName = name;

dbParameter.Value = value;

return objCommand.Parameters.Add(dbParameter);

}

08. May, 2010 0 Comments by admin

In the first part of this series of articles on Data Access Layer, we have had a look at what the

ning and implementing a Generic Data Access Layer. We have had a look

at the enumerators and the factory classes that we will be using. In this part of this article of three

series, we will discuss how we can implement the DatabaseHelper class, one th

responsible for performing the actual database operations.

The DatabaseHelper class encapsulates the various calls to the database to perform the CRUD

operations. The DBManager class that we will discuss later acts as a wrapper on top of this

You have various methods in the DatabaseHelper class to add parameters, to execute queries,

Here is the code that illustrates how the connection to the database is established based on the

provider type chosen and the command object created.

public DatabaseHelper(string connectionstring, ProviderType provider)

this.strConnectionString = connectionstring;

objFactory = DBFactory.GetProvider(provider);

objConnection = objFactory.CreateConnection();

objCommand = objFactory.CreateCommand();

objConnection.ConnectionString = this.strConnectionString;

objCommand.Connection = objConnection;

In ADO.NET, you have the following data providers.

SQL Server Data Provider

Note: Depending on the data provider used, you need to use the command object that is specific

to that provider. Your data reader should also be specific to the data provider used. The use of

in the code snippet above. Note that you use the command objects

to execute the database commands that contain the SQL statements. Added to this, we will have

overloaded versions of AddParameter method to add parameters to the command objects so that

an pass parameters to the database stored procedures or SQL statements. Here is the

simplest version of the AddParameter method.

internal int AddParameter(string name, object value)

DbParameter dbParameter = objFactory.CreateParameter();

Parameter.ParameterName = name;

dbParameter.Value = value;

return objCommand.Parameters.Add(dbParameter);

In the first part of this series of articles on Data Access Layer, we have had a look at what the

ning and implementing a Generic Data Access Layer. We have had a look

at the enumerators and the factory classes that we will be using. In this part of this article of three

series, we will discuss how we can implement the DatabaseHelper class, one that would be

The DatabaseHelper class encapsulates the various calls to the database to perform the CRUD

operations. The DBManager class that we will discuss later acts as a wrapper on top of this class.

You have various methods in the DatabaseHelper class to add parameters, to execute queries,

Here is the code that illustrates how the connection to the database is established based on the

public DatabaseHelper(string connectionstring, ProviderType provider)

objConnection.ConnectionString = this.strConnectionString;

Note: Depending on the data provider used, you need to use the command object that is specific

to that provider. Your data reader should also be specific to the data provider used. The use of

in the code snippet above. Note that you use the command objects

to execute the database commands that contain the SQL statements. Added to this, we will have

overloaded versions of AddParameter method to add parameters to the command objects so that

an pass parameters to the database stored procedures or SQL statements. Here is the

Page 6: Implementing a Generic Data Access Layer in ADO.NET

While the ParameterName identifies the unique name of the parameter to be passed, the Value

implies the value of the parameter passed. Hence, if the ParameterName comprises of

“@EmpName”, the Parameter’s value might be “Joydip Kanjilal”.

In order to ensure that our DataAccessLayer supports transactions, we have three methods that

enable support for transactions. Fine, but what is a transaction? A transaction is an unit of work

that is guaranteed to be executed in its entirety or not executed at all. Here are those methods.

internal void BeginTransaction()

{

if(objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

objCommand.Transaction = objConnection.BeginTransaction();

}

internal void CommitTransaction()

{

objCommand.Transaction.Commit();

objConnection.Close();

}

internal void RollbackTransaction()

{

objCommand.Transaction.Rollback();

objConnection.Close();

}

Note that we have methods that correspond to beginning, commiting or rolling a transaction back

to revert the changes.

We will have the following four methods for performing the CRUD (Create, Update, Read and

Delete) operations in the database. These methods are:

ExecuteScalar()

ExecuteReader()

ExecuteNonQuery()

ExecuteDataSet()

The ExecuteScalar() method is used to read one value from the database. The ExecuteReader()

method returns a DataReader instance from the database populated with rows of data. The

ExecuteNonQuery() method is used to insert, update or delete data either using SQL statements

or using stored procedures.

Page 7: Implementing a Generic Data Access Layer in ADO.NET

The following is the complete code for the DatabaseHelper class.

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

using System.Configuration;

using System.Data.Common;

using System.Data.SqlClient;

using System.Data.OleDb;

using System.Data.Odbc;

using System.IO;

using ApplicationFramework.Configuration;

namespace ApplicationFramework.DataAccessLayer

{

public class DatabaseHelper : IDisposable

{

private string strConnectionString;

private DbConnection objConnection;

private DbCommand objCommand;

private DbProviderFactory objFactory = null;

private ParameterCache parameterCache =

ParameterCache.GetParameterCache();

public DatabaseHelper(string connectionstring, ProviderType provider)

{

this.strConnectionString = connectionstring;

objFactory = DBFactory.GetProvider(provider);

objConnection = objFactory.CreateConnection();

objCommand = objFactory.CreateCommand();

objConnection.ConnectionString = this.strConnectionString;

objCommand.Connection = objConnection;

}

internal int AddParameter(string name, object value)

{

DbParameter dbParameter = objFactory.CreateParameter();

dbParameter.ParameterName = name;

dbParameter.Value = value;

return objCommand.Parameters.Add(dbParameter);

}

internal int AddParameter(DbParameter parameter)

{

return objCommand.Parameters.Add(parameter);

}

internal int AddParameter(string name, StoredProcedureParameterDirection

parameterDirection)

{

DbParameter parameter = objFactory.CreateParameter();

parameter.ParameterName = name;

parameter.Value = String.Empty;

parameter.DbType = DbType.String;

parameter.Size = 50;

Page 8: Implementing a Generic Data Access Layer in ADO.NET

switch (parameterDirection)

{

case StoredProcedureParameterDirection.Input:

parameter.Direction = System.Data.ParameterDirection.Input;

break;

case StoredProcedureParameterDirection.Output:

parameter.Direction = System.Data.ParameterDirection.Output;

break;

case StoredProcedureParameterDirection.InputOutput:

parameter.Direction=System.Data.ParameterDirection.InputOutput;

break;

case StoredProcedureParameterDirection.ReturnValue:

parameter.Direction=System.Data.ParameterDirection.ReturnValue;

break;

}

return objCommand.Parameters.Add(parameter);

}

internal int AddParameter(string name, object value,

StoredProcedureParameterDirection parameterDirection)

{

DbParameter parameter = objFactory.CreateParameter();

parameter.ParameterName = name;

parameter.Value = value;

parameter.DbType = DbType.String;

parameter.Size = 50;

switch (parameterDirection)

{

case StoredProcedureParameterDirection.Input:

parameter.Direction = System.Data.ParameterDirection.Input;

break;

case StoredProcedureParameterDirection.Output:

parameter.Direction = System.Data.ParameterDirection.Output;

break;

case StoredProcedureParameterDirection.InputOutput:

parameter.Direction = System.Data.ParameterDirection.InputOutput;

break;

case StoredProcedureParameterDirection.ReturnValue:

parameter.Direction = System.Data.ParameterDirection.ReturnValue;

break;

}

return objCommand.Parameters.Add(parameter);

}

internal int AddParameter(string name, StoredProcedureParameterDirection

parameterDirection, int size, DbType dbType)

{

DbParameter parameter = objFactory.CreateParameter();

parameter.ParameterName = name;

parameter.DbType = dbType;

parameter.Size = size;

switch (parameterDirection)

{

case StoredProcedureParameterDirection.Input:

parameter.Direction = System.Data.ParameterDirection.Input;

break;

Page 9: Implementing a Generic Data Access Layer in ADO.NET

case StoredProcedureParameterDirection.Output:

parameter.Direction = System.Data.ParameterDirection.Output;

break;

case StoredProcedureParameterDirection.InputOutput:

parameter.Direction=System.Data.ParameterDirection.InputOutput;

break;

case StoredProcedureParameterDirection.ReturnValue:

parameter.Direction=System.Data.ParameterDirection.ReturnValue;

break;

}

return objCommand.Parameters.Add(parameter);

}

internal int AddParameter(string name, object value,

StoredProcedureParameterDirection parameterDirection,

int size, DbType dbType)

{

DbParameter parameter = objFactory.CreateParameter();

parameter.ParameterName = name;

parameter.Value = value;

parameter.DbType = dbType;

parameter.Size = size;

switch (parameterDirection)

{

case StoredProcedureParameterDirection.Input:

parameter.Direction = System.Data.ParameterDirection.Input;

break;

case StoredProcedureParameterDirection.Output:

parameter.Direction = System.Data.ParameterDirection.Output;

break;

case StoredProcedureParameterDirection.InputOutput:

parameter.Direction = System.Data.ParameterDirection.InputOutput;

break;

case StoredProcedureParameterDirection.ReturnValue:

parameter.Direction = System.Data.ParameterDirection.ReturnValue;

break;

}

return objCommand.Parameters.Add(parameter);

}

internal DbCommand Command { get { return objCommand; } }

internal DbConnection Connection { get { return objConnection; } }

internal void BeginTransaction()

{

if(objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

objCommand.Transaction = objConnection.BeginTransaction();

}

Page 10: Implementing a Generic Data Access Layer in ADO.NET

internal void CommitTransaction()

{

objCommand.Transaction.Commit();

objConnection.Close();

}

internal void RollbackTransaction()

{

objCommand.Transaction.Rollback();

objConnection.Close();

}

internal int ExecuteNonQuery(string query)

{

return ExecuteNonQuery(query, CommandType.Text,

DatabaseConnectionState.CloseOnExit);

}

internal int ExecuteNonQuery(string query, CommandType commandtype)

{

return ExecuteNonQuery(query, commandtype,

DatabaseConnectionState.CloseOnExit);

}

internal int ExecuteNonQuery(string query,

DatabaseConnectionState connectionstate)

{

return ExecuteNonQuery(query, CommandType.Text, connectionstate);

}

internal int ExecuteNonQuery(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

objCommand.CommandText = query;

objCommand.CommandType = commandtype;

int i = -1;

try

{

If (objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

i = objCommand.ExecuteNonQuery();

}

catch

{

throw;

}

finally

{

if(connectionstate == DatabaseConnectionState.CloseOnExit)

{

objConnection.Close();

}

}

return i;

}

Page 11: Implementing a Generic Data Access Layer in ADO.NET

internal object ExecuteScalar(string query)

{

return ExecuteScalar(query, CommandType.Text,

DatabaseConnectionState.CloseOnExit);

}

internal object ExecuteScalar(string query, CommandType commandtype)

{

return ExecuteScalar(query, commandtype,

DatabaseConnectionState.CloseOnExit);

}

internal object ExecuteScalar(string query,

DatabaseConnectionState connectionstate)

{

return ExecuteScalar(query, CommandType.Text, connectionstate);

}

internal object ExecuteScalar(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

objCommand.CommandText = query;

objCommand.CommandType = commandtype;

object o = null;

try

{

if(objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

o = objCommand.ExecuteScalar();

}

catch

{

throw;

}

finally

{

objCommand.Parameters.Clear();

if(connectionstate == DatabaseConnectionState.CloseOnExit)

{

objConnection.Close();

}

}

return o;

}

internal DbDataReader ExecuteReader(string query)

{

return ExecuteReader(query, CommandType.Text,

DatabaseConnectionState.CloseOnExit);

}

Page 12: Implementing a Generic Data Access Layer in ADO.NET

internal DbDataReader ExecuteReader(string query, CommandType commandtype)

{

return ExecuteReader(query, commandtype,

DatabaseConnectionState.CloseOnExit);

}

internal DbDataReader ExecuteReader(string query,

DatabaseConnectionState connectionstate)

{

return ExecuteReader(query, CommandType.Text, connectionstate);

}

internal DbDataReader ExecuteReader(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

objCommand.CommandText = query;

objCommand.CommandType = commandtype;

DbDataReader reader = null;

try

{

if(objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

if(connectionstate == DatabaseConnectionState.CloseOnExit)

{

reader = objCommand.ExecuteReader(CommandBehavior.CloseConnection);

}

else

{

reader = objCommand.ExecuteReader();

}

}

catch { }

finally { objCommand.Parameters.Clear(); }

return reader;

}

internal DataSet ExecuteDataSet(string query)

{

return ExecuteDataSet(query, CommandType.Text,

DatabaseConnectionState.CloseOnExit);

}

internal DataSet ExecuteDataSet(string query, CommandType commandtype)

{

return ExecuteDataSet(query, commandtype,

DatabaseConnectionState.CloseOnExit);

}

internal DataSet ExecuteDataSet(string query,

DatabaseConnectionState connectionstate)

{

return ExecuteDataSet(query, CommandType.Text, connectionstate);

}

Page 13: Implementing a Generic Data Access Layer in ADO.NET

internal DataSet ExecuteDataSet(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

DbDataAdapter adapter = objFactory.CreateDataAdapter();

objCommand.CommandText = query;

objCommand.CommandType = commandtype;

adapter.SelectCommand = objCommand;

DataSet ds = new DataSet();

try

{

adapter.Fill(ds);

}

catch

{

throw;

}

finally

{

objCommand.Parameters.Clear();

if(connectionstate == DatabaseConnectionState.CloseOnExit)

{

if(objConnection.State == System.Data.ConnectionState.Open)

{

objConnection.Close();

}

}

}

return ds;

}

public void Dispose()

{

if (objConnection.State == ConnectionState.Open)

{

objConnection.Close();

objConnection.Dispose();

}

objCommand.Dispose();

}

internal IDataReader ExecuteReader(string storedProcedureName,

params object[] parameters)

{

objCommand.CommandText = storedProcedureName;

objCommand.CommandType = CommandType.StoredProcedure;

DbDataReader reader = null;

try

{

RetrieveParameters(objCommand);

SetParameterValues(objCommand, parameters);

if(objConnection.State == System.Data.ConnectionState.Closed)

{

objConnection.Open();

}

reader = objCommand.ExecuteReader();

}

Page 14: Implementing a Generic Data Access Layer in ADO.NET

catch

{

throw;

}

finally

{

objCommand.Parameters.Clear();

}

return reader;

}

internal void SetParameterValues(DbCommand objCommand, object[] parameters)

{

int index = 0;

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

{

DbParameter parameter = objCommand.Parameters[i + index];

SetParameterValue(objCommand, parameter.ParameterName, parameters[i]);

}

}

internal virtual void SetParameterValue(DbCommand dbCommand,

string parameterName, object value)

{

dbCommand.Parameters[parameterName].Value =

(value == null) ? DBNull.Value : value;

}

internal void RetrieveParameters(DbCommand dbCommand)

{

if (parameterCache.ContainsParameters(Connection.ConnectionString,

dbCommand.CommandText))

{

DbParameter[] parameters =

parameterCache.GetParameters(Connection.ConnectionString,

dbCommand.CommandText);

dbCommand.Parameters.AddRange(parameters);

}

else

{

string connectionString = Connection.ConnectionString;

dbCommand.Connection = Connection;

Connection.Open();

SqlCommandBuilder.DeriveParameters(dbCommand as SqlCommand);

parameterCache.AddParameters(connectionString, dbCommand.CommandText,

dbCommand.Parameters);

}

}

internal object GetParameter(string name)

{ return objCommand.Parameters[name].Value; }

}

}

Page 15: Implementing a Generic Data Access Layer in ADO.NET

Conclusion

In the concluding part of this series we will discuss how we can create a wrapper class that

encapsulates the DBHelper class and how we can use that

operations in our database.

Part 3 14. May, 2010

In this the final article of this series,

we can use this framework to perform various CRUD operations in our applications.

Let us start from where we left off in the previous part of this series. Note that most of the

methods of the DatabaseHelper class have been marked

called outside of the “ApplicationFramework.DataAccessLayer” namespace.

Now we will come to the DBManager class; the wrapper class that encapsulates the calls to

another class called DBHelper that actually performs

database. The DBManager class extends the DBManagerBase abstract class. The

DBManagerBase class contains the definition for the Open () and the Close () methods and some

other public properties that are generic and can

will have a look at the DBManagerBase class first.

The following code listing shows the DBManagerBase class.

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

using System.Configuration;

using System.Data.Common;

using System.Data.SqlClient;

using System.Data.OleDb;

using System.Data.Odbc;

using System.IO;

namespace ApplicationFramework.DataAccessLayer

{

public abstract class DBManagerBase

{

protected DatabaseHelper da

protected DbDataReader dbDataReader = null;

protected DataSet dataSet = null;

protected ProviderType providerType;

protected String connectionString = String.Empty;

protected bool isOpen = false;

In the concluding part of this series we will discuss how we can create a wrapper class that

encapsulates the DBHelper class and how we can use that class to perform the various CRUD

0 Comments by admin

article of this series, I will discuss the other classes in this framework and how

we can use this framework to perform various CRUD operations in our applications.

Let us start from where we left off in the previous part of this series. Note that most of the

methods of the DatabaseHelper class have been marked as “internal” to prevent them from being

called outside of the “ApplicationFramework.DataAccessLayer” namespace.

Now we will come to the DBManager class; the wrapper class that encapsulates the calls to

another class called DBHelper that actually performs the CRUD operations on the underlying

database. The DBManager class extends the DBManagerBase abstract class. The

DBManagerBase class contains the definition for the Open () and the Close () methods and some

other public properties that are generic and can be used by any class that acts as a wrapper. We

will have a look at the DBManagerBase class first.

The following code listing shows the DBManagerBase class.

using System.Collections.Generic;

.Configuration;

using System.Data.SqlClient;

namespace ApplicationFramework.DataAccessLayer

public abstract class DBManagerBase

protected DatabaseHelper databaseHelper = null;

protected DbDataReader dbDataReader = null;

protected DataSet dataSet = null;

protected ProviderType providerType;

protected String connectionString = String.Empty;

protected bool isOpen = false;

In the concluding part of this series we will discuss how we can create a wrapper class that

class to perform the various CRUD

in this framework and how

we can use this framework to perform various CRUD operations in our applications.

Let us start from where we left off in the previous part of this series. Note that most of the

as “internal” to prevent them from being

Now we will come to the DBManager class; the wrapper class that encapsulates the calls to

the CRUD operations on the underlying

database. The DBManager class extends the DBManagerBase abstract class. The

DBManagerBase class contains the definition for the Open () and the Close () methods and some

be used by any class that acts as a wrapper. We

Page 16: Implementing a Generic Data Access Layer in ADO.NET

public bool IsOpen

{

get { return isOpen; }

set { isOpen = value; }

}

public string ConnectionString

{

get { return connectionString; }

set { connectionString = value; }

}

public DbConnection Connection

{

get { return databaseHelper.Connection; }

}

public DbCommand Command

{

get { return databaseHelper.Command; }

}

public ProviderType DBProvider

{

set { providerType = value; }

get { return providerType; }

}

public DataSet DBSet

{

get { return dataSet; }

}

public DbDataReader DBReader

{

get { return dbDataReader; }

}

protected void Open(string connectionString)

{

databaseHelper = new DatabaseHelper(connectionString, DBProvider);

}

protected void Close()

{

if (dbDataReader != null)

if (!dbDataReader.IsClosed)

dbDataReader.Close();

databaseHelper.Dispose();

}

public void BeginTransaction() { databaseHelper.BeginTransaction(); }

public void CommitTransaction() { databaseHelper.CommitTransaction(); }

public void RollbackTransaction(){ databaseHelper.RollbackTransaction(); }

}

}

Page 17: Implementing a Generic Data Access Layer in ADO.NET

Note that the DBManagerBase class contains the most common methods that are required. You

can Open or Close a connection, Begin, Commit or Rollback transactions, etc. These methods

would remain the same and are mandatory in this context even if you decide to have another

version of the DBManager class with some more methods implemented it.

The DBManager class that extends the DBManagerBase abstract class contains a list of methods

that can be used to execute stored procedures, queries and return DataSet instance or DataReader

instances as well. You can opt for keeping your connection open after the ExecuteReader method

is called so that you can use the live connection in the subsequent operations that you need to

perform on your database. The methods names in the DBManager class relate to the operations

that they are meant to perform. I feel not you will have any problems understanding what each of

these methods are supposed to do.

Then, you have the AddParameter method that can be used to add parameters to your stored

procedure so that at the time of invoking the procedure, you can pass the parameters along. The

connection string that we need to use to connect to our database can be set using the

ConnectionString public property. The connection string can typically be stored in your

configuration file and the DBManager class can read the configuration file to retrieve the

connection string.

The provider type can be set using the ProviderType enum. Fine, but, where will these values be

set, i.e., how can we call the DBManager and from where? Confused? Hang on. Let us have a

look at the DBManager class followed by how we can use this class to perform CRUD

operations.

The following code listing depicts the DBManager class.

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

using System.Configuration;

using System.Data.Common;

using System.Data.SqlClient;

using System.Data.OleDb;

using System.Data.Odbc;

using System.IO;

namespace ApplicationFramework.DataAccessLayer

{

public sealed class DBManager : DBManagerBase

{

public void OpenConnection()

{

connectionString =

ConfigurationSettings.AppSettings["ConnectionString"].ToString();

base.Open(connectionString);

}

Page 18: Implementing a Generic Data Access Layer in ADO.NET

public void OpenConnection(String connectionString)

{

base.Open(connectionString);

base.IsOpen = true;

}

public void CloseConnection()

{

if (base.isOpen)

base.Close();

base.IsOpen = false;

}

public int AddParameter(string name, object value)

{

return databaseHelper.AddParameter(name, value);

}

public int AddParameter(string name,

StoredProcedureParameterDirection parameterDirection)

{

return databaseHelper.AddParameter(name, parameterDirection);

}

public int AddParameter(string name, object value,

StoredProcedureParameterDirection parameterDirection)

{

return databaseHelper.AddParameter(name, value, parameterDirection);

}

public int AddParameter(string name, StoredProcedureParameterDirection

parameterDirection, int size, DbType dbType)

{

return databaseHelper.AddParameter(name, parameterDirection,

size, dbType);

}

public int AddParameter(string name, object value,

StoredProcedureParameterDirection parameterDirection,

int size, DbType dbType)

{

return databaseHelper.AddParameter(name, value, parameterDirection,

size, dbType);

}

public object GetParameter(string name)

{

return databaseHelper.GetParameter(name);

}

public DbDataReader ExecuteReader(string query)

{

this.dbDataReader = databaseHelper.ExecuteReader(query);

return this.dbDataReader;

}

Page 19: Implementing a Generic Data Access Layer in ADO.NET

public DbDataReader ExecuteReader(string query, CommandType commandtype)

{

this.dbDataReader = databaseHelper.ExecuteReader(query, commandtype,

DatabaseConnectionState.CloseOnExit);

return this.dbDataReader;

}

public IDataReader ExecuteReader(string storedProcedureName,

params object[] parameters)

{

this.dbDataReader = (DbDataReader) databaseHelper.ExecuteReader(

storedProcedureName, parameters);

return this.dbDataReader;

}

public DbDataReader ExecuteReader(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

this.dbDataReader = databaseHelper.ExecuteReader(query, commandtype,

connectionstate);

return this.dbDataReader;

}

public DbDataReader ExecuteReader(string query,

DatabaseConnectionState connectionstate)

{

this.dbDataReader = databaseHelper.ExecuteReader(query, connectionstate);

return this.dbDataReader;

}

public object ExecuteScalar(string query)

{

return databaseHelper.ExecuteScalar(query);

}

public object ExecuteScalar(string query, CommandType commandtype)

{

return databaseHelper.ExecuteScalar(query, commandtype);

}

public object ExecuteScalar(string query,

DatabaseConnectionState connectionstate)

{

return databaseHelper.ExecuteScalar(query, connectionstate);

}

public object ExecuteScalar(string query, CommandType commandtype,

DatabaseConnectionState connectionstate)

{

return databaseHelper.ExecuteScalar(query, commandtype, connectionstate);

}

public DataSet ExecuteDataSet(string query)

{

this.dataSet = databaseHelper.ExecuteDataSet(query);

return this.dataSet;

}

Page 20: Implementing a Generic Data Access Layer in ADO.NET

public DataSet ExecuteDataSet(string query, CommandType commandtype)

{

this.dataSet = databaseHelper.ExecuteDataSet(query, commandtype);

return this.dataSet;

}

public int ExecuteNonQuery(string query, CommandType commandtype)

{

return databaseHelper.ExecuteNonQuery(query, commandtype);

}

public int ExecuteNonQuery(string query, CommandType commandtype,

DatabaseConnectionState databaseConnectionState)

{

return databaseHelper.ExecuteNonQuery(query, commandtype,

databaseConnectionState);

}

}

}

Using the DBManager class

You can make use of the DBManager class as shown in the code snippet below.

DBManager dbManager = new DBManager();

dbManager.OpenConnection();

dbManager.ExecuteReader("Select * from employee");

while (dbManager.DBReader.Read())

Response.Write(dbManager.DBReader[“EmpName”].ToString());

dbManager.CloseConnection();

Note that the OpenConnection and the CloseConnection methods of the DBManager class

invoke the Open and the Close methods of the DBManagerBase class internally.

Similarly, you can use the DBManager class to insert data as shown in the code snippet below.

DBManager dbManager = new DBManager();

String sql = "insert into employee (EmpCode, EmpName)

values ('E001''Joydip')";

try

{ dbManager.OpenConnection();

dbManager.ExecuteNonQuery(sql,CommandType.Text);

}

catch(Exception e)

{ HttpContext.Current.Response.Write(e); }

finally

{

dbManager.CloseConnection();

HttpContext.Current.Response.Write("<BR>"+"1 record added...");

}

Page 21: Implementing a Generic Data Access Layer in ADO.NET

Conclusion

We have had a look at the strategies involved in the design and implementation of a Generic

DAL framework in this series of articles on the Data Access Layer. Let me kno

views/comments by sending me mails at

http://aspadvice.com/blogs/joydip

Working with ADO.NET Transactions

25. Jul, 2010 0 Comments by

A transaction is a group of operations combined into a logical unit of work that is either

guaranteed to be executed as a whole or rolled back. Transactions help the database in satisfying

all the ACID (Atomic, Consistent, Isolated, and Durable). Transaction processing is an

indispensible part of ADO.NET. It guarantees that a block of statements will either be e

in its entirety or rolled back,( i.e., none of the statements will be executed). Transaction

processing has improved a lot in ADO.NET 2.0. This article discusses how we can work with

transactions in both ADO.NET 1.1 and 2.0.

Implementing Transactions in ADO.NET

Note that in ADO.NET, the transactions are started by calling the BeginTransaction method of

the connection class. This method returns an object of type SqlTransaction. Other ADO.NET

connection classes like OleDbConnection, OracleConnection a

you are done executing the necessary statements within the transaction unit/block, make a call to

the Commit method of the given SqlTransaction object, or you can roll back the transaction

using the Rollback method, depending

transaction unit/block was executed).

To work with transactions in ADO.NET, you require an open connection instance and a

transaction instance. Then you need to invoke the necessary methods as stated late

article. Transactions are supported in ADO.NET by the SqlTransaction class that belongs to the

System.Data.SqlClient namespace.

The two main properties of this class are as follows:

• Connection: This indicates the SqlConnection instance that the

associated with

• IsolationLevel: This specifies the IsolationLevel of the transaction

The following are the methods of this class that are noteworthy:

Commit() This method is called to commit the transaction

Rollback() This method can be invoked to roll back a transaction. Note that a transaction can

We have had a look at the strategies involved in the design and implementation of a Generic

DAL framework in this series of articles on the Data Access Layer. Let me kno

views/comments by sending me mails at [email protected]

http://aspadvice.com/blogs/joydip.

Working with ADO.NET Transactions

by admin

A transaction is a group of operations combined into a logical unit of work that is either

executed as a whole or rolled back. Transactions help the database in satisfying

all the ACID (Atomic, Consistent, Isolated, and Durable). Transaction processing is an

indispensible part of ADO.NET. It guarantees that a block of statements will either be e

in its entirety or rolled back,( i.e., none of the statements will be executed). Transaction

processing has improved a lot in ADO.NET 2.0. This article discusses how we can work with

transactions in both ADO.NET 1.1 and 2.0.

ns in ADO.NET

Note that in ADO.NET, the transactions are started by calling the BeginTransaction method of

the connection class. This method returns an object of type SqlTransaction. Other ADO.NET

connection classes like OleDbConnection, OracleConnection also have similar methods. Once

you are done executing the necessary statements within the transaction unit/block, make a call to

the Commit method of the given SqlTransaction object, or you can roll back the transaction

using the Rollback method, depending on your requirements (if any error occurs when the

transaction unit/block was executed).

To work with transactions in ADO.NET, you require an open connection instance and a

transaction instance. Then you need to invoke the necessary methods as stated late

Transactions are supported in ADO.NET by the SqlTransaction class that belongs to the

System.Data.SqlClient namespace.

The two main properties of this class are as follows:

This indicates the SqlConnection instance that the transaction instance is

This specifies the IsolationLevel of the transaction

The following are the methods of this class that are noteworthy:

This method is called to commit the transaction

can be invoked to roll back a transaction. Note that a transaction can

We have had a look at the strategies involved in the design and implementation of a Generic

DAL framework in this series of articles on the Data Access Layer. Let me know your

[email protected]. I blog at

Working with ADO.NET Transactions

A transaction is a group of operations combined into a logical unit of work that is either

executed as a whole or rolled back. Transactions help the database in satisfying

all the ACID (Atomic, Consistent, Isolated, and Durable). Transaction processing is an

indispensible part of ADO.NET. It guarantees that a block of statements will either be executed

in its entirety or rolled back,( i.e., none of the statements will be executed). Transaction

processing has improved a lot in ADO.NET 2.0. This article discusses how we can work with

Note that in ADO.NET, the transactions are started by calling the BeginTransaction method of

the connection class. This method returns an object of type SqlTransaction. Other ADO.NET

lso have similar methods. Once

you are done executing the necessary statements within the transaction unit/block, make a call to

the Commit method of the given SqlTransaction object, or you can roll back the transaction

on your requirements (if any error occurs when the

To work with transactions in ADO.NET, you require an open connection instance and a

transaction instance. Then you need to invoke the necessary methods as stated later in this

Transactions are supported in ADO.NET by the SqlTransaction class that belongs to the

transaction instance is

can be invoked to roll back a transaction. Note that a transaction can

Page 22: Implementing a Generic Data Access Layer in ADO.NET

only be rolled back after it has been committed.

Save() This method creates a save point in the transaction. This save point can be used to

rollback a portion of the transaction at a later point in time. The following are the steps to

implement transaction processing in ADO.NET.

• Connect to the database

• Create a SqlCommand instance with the necessary parameters

• Open the database connection using the connection instance

• Call the BeginTransaction method of the Connection object to mark the beginning of the

transaction

• Execute the sql statements using the command instance

• Call the Commit method of the Transaction object to complete the

transaction, or the Rollback method to cancel or abort the transaction

• Close the connection to the database

The following code snippet shows how we can implement transaction processing using

ADO.NET in our applications.

string connectionString = ...; //Some connection string

SqlConnection sqlConnection = new SqlConnection(connectionString);

sqlConnection.Open();

SqlTransaction sqlTransaction = sqlConnection.BeginTransaction();

SqlCommand sqlCommand = new SqlCommand();

sqlCommand.Transaction = sqlTransaction;

try

{

sqlCommand.CommandText = "Insert into Employee (EmpCode, EmpName)

VALUES (1, 'Joydip')";

sqlCommand.ExecuteNonQuery();

sqlCommand.CommandText = "Insert into Dept (DeptCode, DeptName, EmpCode)

VALUES (9, 'Software', 1)";

sqlCommand.ExecuteNonQuery();

sqlTransaction.Commit();

//Usual code

}

catch(Exception e)

{

sqlTransaction.Rollback();

//Usual code

}

finally

{

sqlConnection.Close();

}

Page 23: Implementing a Generic Data Access Layer in ADO.NET

The next piece of code illustrates how we can use the “using” statement for the above code.

According to MSDN, the “using” statement, “defines a scope, outside of which an object or

objects will be disposed. A using statement can be exited either when the end of the using

statement is reached or if an exception is thrown and control leaves the statement block before

the end of the statement”.

using (SqlConnection sqlConnection = new SqlConnection(connectionString))

{

SqlCommand command = connection.CreateCommand();

SqlTransaction transaction = null;

try

{

sqlConnection.Open();

transaction = sqlConnection.BeginTransaction();

command.Transaction = transaction;

command.CommandText = "Insert into employee (empID, empName) values (1,

'Joydip');

command.ExecuteNonQuery();

command.CommandText = "Insert into dept (deptID,deptName,empID) values

(9,'Software',1)";

command.ExecuteNonQuery();

transaction.Commit();

}

catch(Exception ex)

{

transaction.Rollback();

throw ex;

}

finally

{

sqlConnection.Close();

}

}

The Microsoft’s ADO.NET version 2.0 added a lot of new features to its earlier counterpart to

add moer flexibility and ease of use. As far as transactions are concerned, a new namespace

called System.Transactions has been introduced that promises a significantly improved support

for distributed transactions. It contains a class called TransactionScope that can run a set of

statements. It can also determine whether the objects in the scope have support for transactions.

If the transaction has completed successfully, the changes are committed to the database else it is

rolled back. We need to specify whether the transaction block is complete by making a call to the

TransactionScope.Complete method explicitly, else, the transaction would be rolled back when

the transaction instance would be discarded by the implicit Dispose method.

The following piece of code illustrates what we have learnt so far in this section.

bool IsConsistent = false;

using (System.Transactions.TransactionScope transactionScope = new

System.Transactions.TransactionScope())

Page 24: Implementing a Generic Data Access Layer in ADO.NET

{

SqlConnection sqlConnection = newSqlConnection(connectionString);

string sqlString = "Update emp set empName = 'Joydip Kanjilal' where empID =

9";

SqlCommand cmd1 = newSqlCommand(sql, cn);

sqlConnection.Open();

cmd1.ExecuteNonQuery();

sqlConnection.Close();

transactionScope.Consistent = IsConsistent;

}

TransactionScope also has support for distributed transactions. We can

implement transactions for multiple database connections using it. The

following piece of code shows how we can implement transactional support for

multiple databases using the TransactionScope class.

using (TransactionScope transactionScope = new TransactionScope())

{

using (SqlConnection codesDatabaseConnection = new

SqlConnection(codesDatabaseConnectionString))

{

SqlCommand sqlCommandCodes = codesDatabaseConnection.CreateCommand();

sqlCommandCodes.CommandText = "Insert Into codes (codeID,codeText) values

(1,'Test')";

codesDatabaseConnection.Open();

sqlCommandCodes.ExecuteNonQuery();

codesDatabaseConnection.Close();

}

using (SqlConnection statesDatabaseConnection = new

SqlConnection(statesDatabaseConnectionString))

{

SqlCommand sqlCommandStates = statesDatabaseConnection.CreateCommand();

sqlCommandStates.CommandText = "Insert into States(stateID,stateName) values

(1, 'Test')";

codesDatabaseConnection.Open();

sqlCommandStates.ExecuteNonQuery();

statesDatabaseConnection.Close();

}

transactionScope.Complete();

}

Points to be noted

It should be noted that the SqlTransaction object returned by the BeginTransaction () method has

to be assigned to the Transaction property of the Command object; else an

InvalidOperationException will be thrown by the application when the first query is executed.

Likewise, the Connection instance should be open by invoking the Open method on it prior to

starting a new transaction; else an InvalidOperationException would be thrown. In order to

improve the performance of applications, we should try to keep the transactions (the transaction

units/blocks that contain the statements to be executed in a batch as a whole) as short as possible.

This will help minimize the lock contention and hence increase throughput. Further, we should

analyze whether or not we actually require a transaction for a batch of statements. Try not to

Page 25: Implementing a Generic Data Access Layer in ADO.NET

unnecessarily have transactional statements in you code as it might have a performance

drawback due to the reasons stated above.

Conclusion

The usage of transactions guarantee the execution of a batch of statements sequentially in its

entirety or roll them back hence preserving the database integrity and data consistency. In a

nutshell, in order to work with transactions, invoke the BeginTransaction() method of the

appropriate database connection instance and then call either the Commit() or Rollback() method

on the returned transaction object reference depending on the circumstances. However, it should

be noted that transactions hold locks and may cause contention issues; they should be as short as

it is possible. Hence, this is a major performance drawback in using transactions in our code.

But, if used properly, it can facilitate the design and implementation of robust applications with

data security and consistency. This article has discusses transactions in details in a lucid

language with code examples to illustrate the concepts.