Microsoft .NET Framework Data Provider for Oracle (`System.Data.OracleClient`) 為 .NET 應用程式提供原生、高效能的 Oracle 存取能力,API 設計與 `SqlClient`、`OleDb` 高度一致。本文系統介紹核心四大類別、特殊資料型別對應、參數化查詢、交易處理、完整 CRUD 範例,助您快速上手。
System.Data.OracleClient ├─ OracleConnection : 連線管理、連線池、交易啟始 ├─ OracleCommand : SQL/預存程序執行、參數集合 ├─ OracleDataReader : 唯讀、順向、資料流讀取 └─ OracleDataAdapter : 離線架構、DataSet 填充、更新回寫
| Oracle 型別 | .NET 型別 | OracleType 枚舉 | 備註 |
|---|---|---|---|
| VARCHAR2 / NVARCHAR2 | String | VarChar | 長度 ≤ 4000 |
| NUMBER(p,s) | Decimal / Double | Number | 精度、小數位可指定 |
| DATE / TIMESTAMP | DateTime | DateTime | 含時區資訊需注意 |
| RAW / LONG RAW | Byte[] | Raw / LongRaw | 二進位資料、加密金鑰 |
| BLOB | Stream / Byte[] | Blob | 大型二進位物件 |
| CLOB / NCLOB | String / Stream | Clob / NClob | 大型字元物件 |
| BFILE | 不支援直接讀取 | BFile | 外部檔案定位器 |
| ROWID / UROWID | String | RowId | 實體位址識別碼 |
| XMLType | XmlReader / String | XmlType | 需 Oracle 9i+ |
CREATE TABLE OracleTypesTable (
MyVarchar2 VARCHAR2(3000),
MyNumber NUMBER(28,4) PRIMARY KEY,
MyDate DATE,
MyRaw RAW(255)
);
INSERT INTO OracleTypesTable
VALUES ('test', 4, TO_DATE('2000-01-11 12:54:01','YYYY-MM-DD HH24:MI:SS'), HEXTORAW('0001020304'));
using (var conn = new OracleConnection(connStr))
using (var cmd = new OracleCommand("SELECT * FROM OracleTypesTable WHERE MyNumber = :num", conn))
{
cmd.Parameters.Add(":num", OracleType.Number).Value = 4;
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine($"Varchar2: {reader.GetString(0)}");
Console.WriteLine($"Number: {reader.GetDecimal(1)}");
Console.WriteLine($"Date: {reader.GetDateTime(2)}");
Console.WriteLine($"Raw: {BitConverter.ToString((byte[])reader.GetValue(3))}");
}
}
}
// Insert
string sql = @"INSERT INTO OracleTypesTable (MyVarchar2, MyNumber, MyDate, MyRaw)
VALUES (:v, :n, :d, :r)";
using (var cmd = new OracleCommand(sql, conn))
{
cmd.Parameters.Add(":v", OracleType.VarChar).Value = "new test";
cmd.Parameters.Add(":n", OracleType.Number).Value = 5;
cmd.Parameters.Add(":d", OracleType.DateTime).Value = DateTime.Now;
cmd.Parameters.Add(":r", OracleType.Raw).Value = new byte[] { 0x05, 0x06, 0x07 };
conn.Open();
int rows = cmd.ExecuteNonQuery();
}
// Update (使用位置參數 :1, :2... 或命名參數)
string updSql = "UPDATE OracleTypesTable SET MyVarchar2 = :v WHERE MyNumber = :n";
// Delete
string delSql = "DELETE FROM OracleTypesTable WHERE MyNumber = :n";
using (var conn = new OracleConnection(connStr))
{
conn.Open();
using (var tx = conn.BeginTransaction(IsolationLevel.ReadCommitted))
{
try
{
// 多筆命令共用交易
new OracleCommand("INSERT ...", conn, tx).ExecuteNonQuery();
new OracleCommand("UPDATE ...", conn, tx).ExecuteNonQuery();
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
}
var adapter = new OracleDataAdapter("SELECT * FROM OracleTypesTable", conn);
var builder = new OracleCommandBuilder(adapter); // 自動產生 Insert/Update/Delete 命令
var ds = new DataSet();
adapter.Fill(ds, "OracleTypesTable");
// 修改資料
ds.Tables["OracleTypesTable"].Rows[0]["MyVarchar2"] = "modified";
// 寫回資料庫
adapter.Update(ds, "OracleTypesTable");
| 陷阱 | 正確做法 |
|---|---|
| 連線字串硬編碼 | 放入 `web.config` ` |
| SQL 字串拼接參數 | **永遠使用參數化命令**,防注入、計畫快取、型別安全 |
| 未關閉連線/Reader | `using` 區塊確保 `Dispose()`、連線回池 |
| 忽略連線池配置 | 依負載調整 `Min Pool Size`、`Max Pool Size`、`Connection Lifetime` |
| DateTime 時區不一致 | 資料庫 `SESSIONTIMEZONE`、應用程式 `DateTimeKind.Utc` 統一處理 |
| RAW/BLOB 大物件處理 | 分塊讀寫 (`GetBytes`/`GetChars`)、避免一次載入巨大記憶體 |
// NuGet: Oracle.ManagedDataAccess.Core
using Oracle.ManagedDataAccess.Client; // 命名空間相同,類別名相同
// NuGet: Oracle.EntityFrameworkCore
// DbContext 配置
options.UseOracle(connectionString);
// LINQ 查詢、遷移、追蹤、影子屬性... 完整 EF Core 體驗
掌握 `System.Data.OracleClient` 核心類別與參數化模式,是維護 Legacy 專案的必備技能;但**所有新專案請直接採用 ODP.NET Managed + EF Core**,享受現代化開發體驗與長期支援保障。