本方案可实现仅修改app.config即可连接不同数据库,但是设计数据库时需要注意各种数据库的数据类型是不一样的。
各种不同数据库的Connection、Command、DataAdapter、Transaction和Parameter都继承自IDbConnection、IDbCommand、IDbDataAdapter、IDbTransaction和IDbDataParameter,用一个工厂来实现接口的实例即可实现连接不同数据库。
首先,需要新建一个类库,命名为DbManager,此类库需要5个文件,
1、创建一个枚举类型:DataProvider.cs
namespace DbManager
{
public enum DataProvider
{
Oracle,
SqlServer,
OleDb,
Odbc,
MySql
}
}
2、创建一个工厂类,用来产生以上不同数据库的实例:DBManagerFactory.cs
using
System.Data;
using
System.Data.Odbc;
using
System.Data.SqlClient;
using
System.Data.OleDb;
using
System.Data.OracleClient; //需要添加引用
using
MySql.Data.MySqlClient; //请自行安装MySQLConnector/Net后添加引用
namespace
DbManager
{
public
sealed
class
DBManagerFactory
{
private
DBManagerFactory()
{
}
public
static
IDbConnection GetConnection(DataProvider providerType)
{
IDbConnection iDbConnection;
switch
(providerType)
{
case
DataProvider.SqlServer:
iDbConnection
=
new
SqlConnection();
break
;
case
DataProvider.OleDb:
iDbConnection
=
new
OleDbConnection();
break
;
case
DataProvider.Odbc:
iDbConnection
=
new
OdbcConnection();
break
;
case
DataProvider.Oracle:
iDbConnection
=
new
OracleConnection();
break
;
case
DataProvider.MySql:
iDbConnection
=
new
MySqlConnection();
break
;
default
:
return
null
;
}
return
iDbConnection;
}
public
static
IDbCommand GetCommand(DataProvider providerType)
{
switch
(providerType)
{
case
DataProvider.SqlServer:
return
new
SqlCommand();
case
DataProvider.OleDb:
return
new
OleDbCommand();
case
DataProvider.Odbc:
return
new
OdbcCommand();
case
DataProvider.Oracle:
return
new
OracleCommand();
case
DataProvider.MySql:
return
new
MySqlCommand();
default
:
return
null
;
}
}
public
static
IDbDataAdapter GetDataAdapter(DataProvider providerType)
{
switch
(providerType)
{
case
DataProvider.SqlServer:
return
new
SqlDataAdapter();
case
DataProvider.OleDb:
return
new
OleDbDataAdapter();
case
DataProvider.Odbc:
return
new
OdbcDataAdapter();
case
DataProvider.Oracle:
return
new
OracleDataAdapter();
case
DataProvider.MySql:
return
new
MySqlDataAdapter();
default
:
return
null
;
}
}
public
static
IDbTransaction GetTransaction(DataProvider providerType)
{
IDbConnection iDbConnection
=
GetConnection(providerType);
IDbTransaction iDbTransaction
=
iDbConnection.BeginTransaction();
return
iDbTransaction;
}
public
static
IDbDataParameter[] GetParameters(DataProvider providerType,
int
paramsCount)
{
IDbDataParameter[] idbParams
=
new
IDbDataParameter[paramsCount];
switch
(providerType)
{
case
DataProvider.SqlServer:
for
(
int
i
=
0
; i
<
paramsCount; i
++
)
{
idbParams[i]
=
new
SqlParameter();
}
break
;
case
DataProvider.OleDb:
for
(
int
i
=
0
; i
<
paramsCount; i
++
)
{
idbParams[i]
=
new
OleDbParameter();
}
break
;
case
DataProvider.Odbc:
for
(
int
i
=
0
; i
<
paramsCount; i
++
)
{
idbParams[i]
=
new
OdbcParameter();
}
break
;
case
DataProvider.Oracle:
for
(
int
i
=
0
; i
<
paramsCount; i
++
)
{
idbParams[i]
=
new
OracleParameter();
}
break
;
case
DataProvider.MySql:
for
(
int
i
=
0
; i
<
paramsCount; i
++
)
{
idbParams[i]
=
new
MySqlParameter();
}
break
;
default
:
idbParams
=
null
;
break
;
}
return
idbParams;
}
}
}
3、创建一个接口:IDBManager.cs
using
System.Data;
namespace
DbManager
{
public
interface
IDBManager
{
DataProvider ProviderType
{
get
;
set
;
}
IDbConnection Connection
{
get
;
set
;
}
IDataReader DataReader
{
get
;
set
;
}
IDbCommand Command
{
get
;
set
;
}
IDbTransaction Transaction
{
get
;
set
;
}
IDbDataParameter[] Parameters
{
get
;
set
;
}
string
ConnectionString
{
get
;
set
;
}
void
Open();
void
Close();
void
Dispose();
void
CreateParameters(
int
paramsCount);
void
AddParameters(
int
index,
string
paramName,
object
objValue);
void
BeginTransaction();
void
CommitTransaction();
void
CloseReader();
IDataReader ExecuteReader(CommandType commandType,
string
commandText);
int
ExecuteNonQuery(CommandType commandType,
string
commandText);
object
ExecuteScalar(CommandType commandType,
string
commandText);
DataSet ExecuteDataSet(CommandType commandType,
string
commandText);
}
}
4、创建一个类来实现IDBManager接口:DBManager.cs
using
System;
using
System.Data;
namespace
DbManager
{
public
sealed
class
DBManager : IDBManager, IDisposable
{
#region
字段
private
DataProvider _providerType;
private
IDbConnection _idbConnection;
private
IDataReader _iDataReader;
private
IDbCommand _idbCommand;
private
IDbTransaction _idbTransaction;
private
IDbDataParameter[] _idbParameters;
private
string
_connectionString;
#endregion
#region
构造方法
public
DBManager()
{
}
public
DBManager(DataProvider providerType)
{
ProviderType
=
providerType;
}
public
DBManager(DataProvider providerType,
string
connectionString)
{
ProviderType
=
providerType;
ConnectionString
=
connectionString;
}
#endregion
#region
属性
public
DataProvider ProviderType
{
get
{
return
_providerType; }
set
{ _providerType
=
value; }
}
public
IDbConnection Connection
{
get
{
return
_idbConnection; }
set
{ _idbConnection
=
value; }
}
public
IDataReader DataReader
{
get
{
return
_iDataReader; }
set
{ _iDataReader
=
value; }
}
public
IDbCommand Command
{
get
{
return
_idbCommand; }
set
{ _idbCommand
=
value; }
}
public
IDbTransaction Transaction
{
get
{
return
_idbTransaction; }
set
{ _idbTransaction
=
value; }
}
public
IDbDataParameter[] Parameters
{
get
{
return
_idbParameters; }
set
{ _idbParameters
=
value; }
}
public
string
ConnectionString
{
get
{
return
_connectionString; }
set
{ _connectionString
=
value; }
}
#endregion
#region
公有方法
public
void
Open()
{
Connection
=
DBManagerFactory.GetConnection(ProviderType);
Connection.ConnectionString
=
ConnectionString;
if
(Connection.State
!=
ConnectionState.Open)
{
Connection.Open();
}
Command
=
DBManagerFactory.GetCommand(ProviderType);
}
public
void
Close()
{
if
(Connection.State
!=
ConnectionState.Closed)
{
Connection.Close();
}
}
public
void
Dispose()
{
GC.SuppressFinalize(
this
);
Close();
Command
=
null
;
Transaction
=
null
;
Connection
=
null
;
}
public
void
CreateParameters(
int
paramsCount)
{
Parameters
=
new
IDbDataParameter[paramsCount];
Parameters
=
DBManagerFactory.GetParameters(ProviderType, paramsCount);
}
public
void
AddParameters(
int
index,
string
paramName,
object
objValue)
{
if
(index
<
Parameters.Length)
{
Parameters[index].ParameterName
=
paramName;
Parameters[index].Value
=
objValue;
}
}
public
void
BeginTransaction()
{
if
(Transaction
==
null
)
{
Transaction
=
DBManagerFactory.GetTransaction(ProviderType);
}
Command.Transaction
=
Transaction;
}
public
void
CommitTransaction()
{
if
(Transaction
!=
null
)
{
Transaction.Commit();
}
Transaction
=
null
;
}
public
void
CloseReader()
{
if
(DataReader
!=
null
)
{
DataReader.Close();
}
}
public
IDataReader ExecuteReader(CommandType commandType,
string
commandText)
{
Command
=
DBManagerFactory.GetCommand(ProviderType);
Command.Connection
=
Connection;
PrepareCommand(Command, Connection, Transaction, commandType, commandText, Parameters);
DataReader
=
Command.ExecuteReader();
Command.Parameters.Clear();
return
DataReader;
}
public
int
ExecuteNonQuery(CommandType commandType,
string
commandText)
{
Command
=
DBManagerFactory.GetCommand(ProviderType);
PrepareCommand(Command, Connection, Transaction, commandType, commandText, Parameters);
int
returnValue
=
Command.ExecuteNonQuery();
Command.Parameters.Clear();
return
returnValue;
}
public
object
ExecuteScalar(CommandType commandType,
string
commandText)
{
Command
=
DBManagerFactory.GetCommand(ProviderType);
PrepareCommand(Command, Connection, Transaction, commandType, commandText, Parameters);
object
returnValue
=
Command.ExecuteScalar();
Command.Parameters.Clear();
return
returnValue;
}
public
DataSet ExecuteDataSet(CommandType commandType,
string
commandText)
{
Command
=
DBManagerFactory.GetCommand(ProviderType);
PrepareCommand(Command, Connection, Transaction, commandType, commandText, Parameters);
IDbDataAdapter dataAdapter
=
DBManagerFactory.GetDataAdapter(ProviderType);
dataAdapter.SelectCommand
=
Command;
DataSet dataSet
=
new
DataSet();
dataAdapter.Fill(dataSet);
Command.Parameters.Clear();
return
dataSet;
}
#endregion
#region
私有方法
private
void
AttachParameters(IDbCommand command, IDbDataParameter[] commandParameters)
{
foreach
(IDbDataParameter idbParameter
in
commandParameters)
{
if
(idbParameter.Direction
==
ParameterDirection.InputOutput
&&
idbParameter.Value
==
null
)
{
idbParameter.Value
=
DBNull.Value;
}
command.Parameters.Add(idbParameter);
}
}
private
void
PrepareCommand(IDbCommand command, IDbConnection connection, IDbTransaction transaction,
CommandType commandType,
string
commandText, IDbDataParameter[] commandParameters)
{
command.Connection
=
connection;
command.CommandText
=
commandText;
command.CommandType
=
commandType;
if
(transaction
!=
null
)
{
command.Transaction
=
transaction;
}
if
(commandParameters
!=
null
)
{
AttachParameters(command, commandParameters);
}
}
#endregion
}
}
5、再加一个DBHelper.cs,来调用DBManager类,外部来直接调用DBHelper类即可。
using
System;
using
System.Data;
using
System.Configuration;
namespace
DbManager
{
public
class
DBHelper
{
private
static
readonly
IDBManager dbManager
=
new
DBManager(GetDataProvider(), GetConnectionString());
///
<summary>
///
从配置文件中选择数据库类型
///
</summary>
///
<returns>
DataProvider枚举值
</returns>
private
static
DataProvider GetDataProvider()
{
string
providerType
=
ConfigurationManager.AppSettings[
"
DataProvider
"
];
DataProvider dataProvider;
switch
(providerType)
{
case
"
Oracle
"
:
dataProvider
=
DataProvider.Oracle;
break
;
case
"
SqlServer
"
:
dataProvider
=
DataProvider.SqlServer;
break
;
case
"
OleDb
"
:
dataProvider
=
DataProvider.OleDb;
break
;
case
"
Odbc
"
:
dataProvider
=
DataProvider.Odbc;
break
;
case
"
MySql
"
:
dataProvider
=
DataProvider.MySql;
break
;
default
:
return
DataProvider.Odbc;
}
return
dataProvider;
}
///
<summary>
///
从配置文件获取连接字符串
///
</summary>
///
<returns>
连接字符串
</returns>
private
static
string
GetConnectionString()
{
return
ConfigurationManager.ConnectionStrings[
"
ConnString
"
].ConnectionString;
}
///
<summary>
///
关闭数据库连接的方法
///
</summary>
public
static
void
Close()
{
dbManager.Dispose();
}
///
<summary>
///
创建参数
///
</summary>
///
<param name="paramsCount">
参数个数
</param>
public
static
void
CreateParameters(
int
paramsCount)
{
dbManager.CreateParameters(paramsCount);
}
///
<summary>
///
添加参数
///
</summary>
///
<param name="index">
参数索引
</param>
///
<param name="paramName">
参数名
</param>
///
<param name="objValue">
参数值
</param>
public
static
void
AddParameters(
int
index,
string
paramName,
object
objValue)
{
dbManager.AddParameters(index, paramName, objValue);
}
///
<summary>
///
执行增删改
///
</summary>
///
<param name="sqlString">
安全的sql语句string.Format()
</param>
///
<returns>
操作成功返回true
</returns>
public
static
bool
ExecuteNonQuery(
string
sqlString)
{
try
{
dbManager.Open();
return
dbManager.ExecuteNonQuery(CommandType.Text, sqlString)
>
0
?
true
:
false
;
}
catch
(Exception e)
{
throw
new
Exception(e.Message);
}
finally
{
dbManager.Dispose();
}
}
///
<summary>
///
执行查询
///
</summary>
///
<param name="sqlString">
安全的sql语句string.Format()
</param>
///
<returns>
返回IDataReader
</returns>
public
static
IDataReader ExecuteReader(
string
sqlString)
{
try
{
dbManager.Open();
return
dbManager.ExecuteReader(CommandType.Text, sqlString);
}
catch
(Exception e)
{
throw
new
Exception(e.Message);
}
}
}
}
现在,将上述项目生成一个DbManager.dll类库,在具体的DAL层里面就可以直接调用了。
DBHelper类没有全部写完,只写了ExecuteNonQuery()和ExecuteReader()两个方法,对于有参和无参的增删改查操作暂时够用,返回DataSet的方法未写,Transaction相关的也未写。
6、app.config
<?
xml version
=
"
1.0
"
encoding
=
"
utf-8
"
?>
<
configuration
>
<
connectionStrings
>
<
add name
=
"
ConnString
"
connectionString
=
"
server=localhost;database=yourDbName;Persist Security Info=False;uid=root;pwd=mysqladmin
"
/>
<!--
通过改变ConnectionString的值来更换数据库连接字符串
<
add name
=
"
ConnString
"
connectionString
=
"
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=DBDemo.mdb;Jet OLEDB:Database Password=1234
"
/>
<
add name
=
"
ConnString
"
connectionString
=
"
server=localhost;database=yourDbName;Persist Security Info=False;Integrated Security=SSPI
"
/>
<
add name
=
"
ConnString
"
connectionString
=
"
server=localhost;database=
yourDbName
;Persist Security Info=False;uid=sa;pwd=
1234"
/>
<
add name
=
"
ConnString
"
connectionString
=
"
server=localhost;database=
yourDbName
;Persist Security Info=False;uid=root;pwd=mysqladmin
"
/>
-->
</
connectionStrings
>
<
appSettings
>
<
add key
=
"
DataProvider
"
value
=
"
MySql
"
/>
<!--
通过改变value值来更换数据库
<
add key
=
"
DataProvider
"
value
=
"
Oracle
"
/>
<
add key
=
"
DataProvider
"
value
=
"
SqlServer
"
/>
<
add key
=
"
DataProvider
"
value
=
"
OleDb
"
/>
<
add key
=
"
DataProvider
"
value
=
"
Odbc
"
/>
<
add key
=
"
DataProvider
"
value
=
"
MySql
"
/>
-->
</
appSettings
>
</
configuration
>
7、程序中的调用
举个简单的例子,我们就创建一个控制台应用程序,然后添加DbManager.dll的引用
Program.cs文件的样子:
using
System;
using
System.Data;
using
DbManager; //记得引入命名空间
namespace
DBDemo
{
class
Program
{
static
void
Main(
string
[] args)
{
SelectWithoutParams();
Console.WriteLine(
"
------安全sql语句string.Format()的查询结果------
"
);
SelectWithSafeSql(
4
);
Console.WriteLine(
"
------参数化语句的查询结果-------
"
);
SelectWithParams(
"
总统套间
"
);
}
private static void SelectWithoutParams()
{
const
string
sql
=
"
select * from RoomType
"
;
IDataReader reader
=
DBHelper.ExecuteReader(sql);
while
(reader.Read())
{
Console.WriteLine(reader[
"
TypeName
"
].ToString());
}
DBHelper.Close(); //记得关闭reader
}
private
static
void
SelectWithSafeSql(
int
TypeId)
{
string
sql
=
string
.Format(
"
select * from RoomType where TypeId={0}
"
, TypeId);
IDataReader reader
=
DBHelper.ExecuteReader(sql);
while
(reader.Read())
{
Console.WriteLine(reader[
"
TypeName
"
].ToString());
}
DBHelper.Close();
}
private
static
void
SelectWithParams(
string
typeName)
{
string sql = "select * from RoomType where TypeName=@TypeName";
//先创建参数,然后才能添加参数
DBHelper.CreateParameters(
1
);
//
参数个数,1个
DBHelper.AddParameters(
0
,
"
@TypeName
"
, typeName);
IDataReader reader
=
DBHelper.ExecuteReader(sql);
while
(reader.Read())
{
Console.WriteLine(reader[
"
TypeName
"
].ToString());
}
DBHelper.Close();
}
}
}
OK!全部完成!在具体的DAL层中,调用DBHelper的相关方法即可,如果是查询方法,记得最后要写关闭代码。只要表结构一样,可以在app.config中随意切换数据库。
最后注意的是:
各个数据库的插入语句不一样,假设我们有4个字段,第一个字段fieldName1为自增字段。
对于SQLServer,不需要写自增字段,
语句是:INSERT INTO table VALUES(value2, value3, value4);
对于MySQL,自增字段位置需要写null代替,
语句是:INSERT INTO table VALUES(NULL, value2, value3, value4);
而对于ACCESS数据库,则必须写完整,
语句是:INSERT INTO table(fieldName2, fieldName3,fieldName4) VALUES(value2, value3, value4);
为了实现兼容,大家还是都按完整的来写,就不会有错了