ADO.NET 核心類別 (Connection、Command、DataReader) 設計為 Provider 獨立模式,僅需更換連線字串與對應的命名空間即可支援不同資料庫。本文對比 Access (OleDb) 與 SQL Server (SqlClient) 兩套完整程式碼。
using System;
using System.Data; // 介面定義
// using System.Data.OleDb; // Access
// using System.Data.SqlClient; // SQL Server
public abstract class DbDemoBase
{
protected abstract IDbConnection CreateConnection(string connStr);
protected abstract IDbCommand CreateCommand(string sql, IDbConnection conn);
public void Run(string connStr)
{
using (IDbConnection conn = CreateConnection(connStr))
{
conn.Open();
using (IDbCommand cmd = CreateCommand("SELECT * FROM Persons", conn))
using (IDataReader reader = cmd.ExecuteReader())
{
Console.WriteLine("欄位數:" + reader.FieldCount);
while (reader.Read())
{
Console.WriteLine(reader[0]); // 第一欄
}
}
}
}
}
using System.Data.OleDb;
public class AccessDemo : DbDemoBase
{
protected override IDbConnection CreateConnection(string connStr)
=> new OleDbConnection(connStr);
protected override IDbCommand CreateCommand(string sql, IDbConnection conn)
=> new OleDbCommand(sql, (OleDbConnection)conn);
}
// 使用
string accessConn = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\MY.MDB";
// 或 ACE Provider (Access 2007+ .accdb)
// Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\MY.accdb;
new AccessDemo().Run(accessConn);
using System.Data.SqlClient; // 或 Microsoft.Data.SqlClient (建議)
public class SqlServerDemo : DbDemoBase
{
protected override IDbConnection CreateConnection(string connStr)
=> new SqlConnection(connStr);
protected override IDbCommand CreateCommand(string sql, IDbConnection conn)
=> new SqlCommand(sql, (SqlConnection)conn);
}
// 使用
string sqlConn = "Server=.;Database=MyDb;User Id=sa;Password=123;TrustServerCertificate=True;";
new SqlServerDemo().Run(sqlConn);
| 項目 | Access (OleDb) | SQL Server (SqlClient) |
|---|---|---|
| Provider 關鍵字 | Provider=Microsoft.Jet.OLEDB.4.0 | 不需要 (內建) |
| 資料來源 | Data Source=路徑 | Server=主機;Database=名稱 |
| 驗證 | 通常無密碼或資料庫密碼 | User Id=sa;Password=xxx 或 Integrated Security=True |
| 檔案鎖定 | 獨佔模式需 Mode=Share Deny None | 連線池自動管理 |
// OleDb: 位置參數 (?) - 順序對應
OleDbCommand cmd = new OleDbCommand("INSERT INTO Persons (Name, Phone) VALUES (?, ?)", conn);
cmd.Parameters.AddWithValue("@p1", "王小明"); // 參數名稱僅為文件用,實際靠順序
cmd.Parameters.AddWithValue("@p2", "02-1234567");
// SqlClient: 命名參數 (@名稱) - 名稱對應
SqlCommand cmd = new SqlCommand("INSERT INTO Persons (Name, Phone) VALUES (@Name, @Phone)", conn);
cmd.Parameters.AddWithValue("@Name", "王小明");
cmd.Parameters.AddWithValue("@Phone", "02-1234567");
.NET 2.0+ 提供 DbProviderFactory 以字串動態建立 Provider 物件,配合 appSettings.json 實現零程式碼切換資料庫。實務上建議直接使用 Entity Framework Core 或 Dapper,進一步抽象 SQL 差異。
// EF Core 範例:同一個 DbContext 類別,換 Provider 即可
services.AddDbContext(o => o.UseSqlServer(connStr));
// 或 o.UseSqlite(connStr) / o.UseNpgsql(connStr) / o.UseMySql(connStr)
Memo → SQL NVARCHAR(MAX);Access DateTime 精度較低。AutoNumber → SQL IDENTITY(1,1)。User、Order),需用 [User] 括號。#2024-01-01# → SQL '2024-01-01'。