玄铁剑

成功的途径:抄,创造,研究,发明...
posts - 128, comments - 42, trackbacks - 0, articles - 174


Introduction

Developers often write applications that use databases. Because it is so common, they need to simplify tasks regarding data access functionality. The applications quite often require to be adapted to suit the programming model of each database.

Background

The System.Data namespace consists mostly of the classes that constitute the ADO.NET architecture. This namespace also defines a number of data access interfaces that could be used from different providers. Have a data access layer component that you could use against an Access 2000 database in development, and against a SQL Server or Oracle database in production should be a dream. Should not it?

How have I thought to do it?

The Liskov Substitution Principle come to help us. It states that derived classes must be usable through the base class interface without the need for the user to know the difference. In other simply words, it means that an object of a class that implements an interface can be upcast to the interface type. I have introduced that because it could helps us to understand a very useful patter called an Abstract Factory. What is the intent of the Abstract Factory patter?

Abstract Factory class diagram

An Abstract Factory Design Pattern provides a contract for creating families of related or dependent objects without having to specify their concrete classes.

  • Participants and Collaborators
    • AbstractFactory
    • ConcreteFactory
    • AbstractProduct
    • ConcreteProduct
    • Client
  • Consequences
    • Isolates concrete classes
    • Makes exchanging product families easy
    • Promotes consistency among products
    • Supporting new kinds of products can be difficult
  • Implementation
    • Abstract Factories are often Singletons
    • Often, a Factory Method is used to create the product

Data Access Layer Interface

We need to create Data Access Layer objects, but we also need the system to be independent of how every single DAL are created. The following code block shows the IDal interface representing the abstract product.

public interface IDal
{
IDbCommand CreateCommand();
IDbCommand CreateCommand( string cmdText );
IDbCommand CreateCommand( string cmdText, IDbConnection cn );
IDbCommand CreateCommand( string cmdText, IDbConnection cn, IDbTransaction trans );
IDbConnection CreateConnection();
IDbConnection CreateConnection( string cnString );
IDbDataAdapter CreateDataAdapter();
IDbDataAdapter CreateDataAdapter( IDbCommand selectCmd );
IDbDataAdapter CreateDataAdapter( string selectCmdText, string selectCnString );
IDbDataAdapter CreateDataAdapter( string selectCmdText, IDbConnection selectCn );
IDataReader CreateDataReader( IDbCommand dbCmd );
IDataReader CreateDataReader( IDbCommand dbCmd, CommandBehavior dbCmdBehavior );
}

Examples Of Implementation

To make independent my in/out parameters of the implementation, I used common interfaces (System.Data) as parameter types. It is time to implement the real product extending the IDAL interface. To do that we have to create a new class I am going to name an OracleDal. Why do I call it OracleDal? Because I want to build a oracle access point. Of course as you could see in the complete source code I have enclosed and clicking the others icons, you could create different objects using many others providers. The example below shows a reduced OracleDal implementation.

Oracle Db2 Sql Server
Click a different icon to view a different implementation

O


R



A



C



L



E

Oracle

public class OracleDal: IDal
{
public IDbCommand CreateCommand( string cmdText, IDbConnection cn, IDbTransaction trans )
{
IDbCommand oracleCmd = null;
try
{
oracleCmd = new OracleCommand( cmdText, (OracleConnection)cn, (OracleTransaction)trans );
}
catch( OracleException oracleExc )
{
if(oracleCmd != null)
oracleCmd.Dispose();
throw new Exception( oracleExc.Message );
}
return oracleCmd;
}
public IDataReader CreateDataReader(IDbCommand dbCmd, CommandBehavior dbCmddBehavior )
{
IDataReader dr = null;
try
{
dr = dbCmd.ExecuteReader( dbCmdBehavior );
}
catch( OracleException oracleExc )
{
if( dr != null)
{
if(!dr.IsClosed)
dr.Close();
dr.Dispose();
}
throw new Exception( oracleExc.Message );
}
return dr;
}
public IDbConnection CreateConnection( string cnString )
{
IDbConnection oracleCn = null;
try
{
oracleCn = new OracleConnection( cnString );
}
catch( OracleException oracleExc )
{
if( oracleCn != null)
oracleCn.Dispose();
throw new Exception( oracleExc.Message );
}
return oracleCn;
}
public IDbDataAdapter CreateDataAdapter( string selectCmdText, IDbConnection selectCn )
{
IDbDataAdapter oracleDataAdapter = null;
try
{
oracleDataAdapter = new OracleDataAdapter( selectCmdText, (OracleConnection)selectCn );
}
catch( OracleException oracleExc )
{
throw new Exception( oracleExc.Message );
}
return oracleDataAdapter;
}
}
O


R



A



C



L



E


Informations

This article description is not complete. I am sorry for that. I am going to insert the other part as soon as possible. If you want you can use the complete source code I have attached. Please contact me for every suggest.

只有注册用户登录后才能发表评论。