企業級應用常面臨多種數據庫共存或遷移需求。本文提供一個基於 ADO.NET 接口(IDbConnection、IDbCommand、IDataAdapter 等)編寫的通用數據訪問基類 DataBaseLayer,通過工廠模式根據配置動態創建具體數據庫提供程序對象,實現 SQL Server、Oracle、Access 三大主流數據庫的**零代碼修改切換**,並封裝了參數化查詢、事務、存儲過程、分頁、XML 導出等常用操作。
類內部持有 DbType("SqlServer"、"Oracle"、"Access")與連接字符串,所有數據庫操作通過 GetConnection、GetCommand、GetAdapter 等工廠方法返回接口類型,業務代碼僅依賴 System.Data 公共接口,與具體提供程序解耦。
private IDbDataParameter CreateParameter(string name, string dataType)
{
switch (DbType)
{
case "SqlServer": return CreateSqlParameter(name, dataType);
case "Oracle": return CreateOracleParameter(name, dataType);
case "Access": return CreateOleDbParameter(name, dataType);
default: return CreateSqlParameter(name, dataType);
}
}
private SqlParameter CreateSqlParameter(string name, string type)
{
switch (type)
{
case "Decimal": return new SqlParameter(name, SqlDbType.Decimal);
case "Varchar": return new SqlParameter(name, SqlDbType.VarChar);
case "DateTime": return new SqlParameter(name, SqlDbType.DateTime);
case "Image": return new SqlParameter(name, SqlDbType.Image);
case "Int": return new SqlParameter(name, SqlDbType.Int);
case "Text": return new SqlParameter(name, SqlDbType.NText);
default: return new SqlParameter(name, SqlDbType.VarChar);
}
}
// OracleParameter、OleDbParameter 同理映射對應類型
private IDbConnection GetConnection()
{
switch (DbType)
{
case "SqlServer": return new SqlConnection(ConnectionString);
case "Oracle": return new OracleConnection(ConnectionString);
case "Access": return new OleDbConnection(ConnectionString);
default: return new SqlConnection(ConnectionString);
}
}
private IDbCommand GetCommand(string sql, IDbConnection conn)
{
switch (DbType)
{
case "SqlServer": return new SqlCommand(sql, (SqlConnection)conn);
case "Oracle": return new OracleCommand(sql, (OracleConnection)conn);
case "Access": return new OleDbCommand(sql, (OleDbConnection)conn);
default: return new SqlCommand(sql, (SqlConnection)conn);
}
}
// GetAdapter 同理
public int ExecuteSql(string sql, params IDataParameter[] parameters)
{
using (IDbConnection conn = GetConnection())
using (IDbCommand cmd = GetCommand())
{
PrepareCommand(cmd, conn, null, sql, parameters);
conn.Open();
try { return cmd.ExecuteNonQuery(); }
finally { if (conn.State != ConnectionState.Closed) conn.Close(); }
}
}
private void PrepareCommand(IDbCommand cmd, IDbConnection conn, IDbTransaction trans, string sql, IDataParameter[] paras)
{
if (conn.State != ConnectionState.Open) conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
if (trans != null) cmd.Transaction = trans;
cmd.CommandType = CommandType.Text;
if (paras != null) foreach (var p in paras) cmd.Parameters.Add(p);
}
| 分類 | 方法示例 | 說明 |
|---|---|---|
| 基本執行 | ExecuteSql(sql)、ExecuteSql(sql, params)、GetSingle(sql) | 增刪改、標量查詢,支持參數化 |
| 事務 | ExecuteSqlTran(ArrayList)、ExecuteSqlTran(Hashtable) | 多語句原子操作,Hashtable 版本支持每條語句獨立參數 |
| 查詢返回 | Query(sql)→DataSet、ExecuteQuery(sql)→DataTable、ExecuteReader(sql)→IDataReader、ExeceuteDataView(sql)→DataView | 多種返回形式滿足不同綁定需求 |
| 分頁查詢 | Query(sql, DataSet, startIndex, pageSize, tableName) | 利用 DataAdapter.Fill 重載實現數據庫端分頁(Access/Oracle 需特定 SQL) |
| XML 導出 | WriteToXml(sql, xmlPath) | 查詢結果直接序列化為 XML 文件 |
| 存儲過程 | RunProcedure 系列(返回 DataReader/DataSet/受影響行數/輸出參數) | 封裝 SqlCommand.CommandType.StoredProcedure,參數自動綁定 |
| 批量/圖片 | ExecuteSqlInsertImg(sql, byte[])、ExecuteSql(sql, content) | 大文本/二進制字段參數化寫入 |
<appSettings>
<add key="ConnectionString" value="server=.;database=MyDB;uid=sa;pwd=123" />
<add key="DataType" value="SqlServer" /> <!-- Oracle / Access -->
</appSettings>
構造函數自動讀取配置,無需硬編碼:
public DataBaseLayer()
{
ConnectionString = ConfigurationSettings.AppSettings["ConnectionString"];
DbType = ConfigurationSettings.AppSettings["DataType"] ?? "Access";
}
// 默認配置
DataBaseLayer db = new DataBaseLayer();
// 參數化查詢
string sql = "SELECT * FROM Users WHERE Age > @Age AND Status = @Status";
IDataParameter[] paras = {
db.CreateParameter("@Age", "Int"),
db.CreateParameter("@Status", "Int")
};
paras[0].Value = 18;
paras[1].Value = 1;
DataSet ds = db.Query(sql, paras);
// 事務批量操作
Hashtable ht = new Hashtable();
ht.Add("INSERT INTO Log(...) VALUES(...)", new IDataParameter[] { ... });
ht.Add("UPDATE Stats SET Count=Count+1 WHERE Id=1", null);
db.ExecuteSqlTran(ht);
System.Data.OracleClient,建議遷移至 Oracle.ManagedDataAccess (NuGet)。async/await 版本(ExecuteNonQueryAsync 等)。這個基類展示了 ADO.NET 接口編程的經典模式,理解其原理有助於深入掌握數據訪問本質,也為遺留系統重構提供參考藍圖。