在 .NET Framework 應用程式中存取 Oracle 資料庫,需正確安裝資料提供者、配置連線字串、處理常見參考缺失與編碼問題。本文以 Windows Forms 專案為例,完整呈現從 NuGet 套件安裝、連線池管理、參數化查詢到 UI 整合的端到端實作。
# Package Manager Console
Install-Package Oracle.ManagedDataAccess
或透過 NuGet 圖形介面搜尋「Oracle.ManagedDataAccess」安裝。此套件無需安裝 Oracle Client,部署極簡單。
System.Data.OracleClient。Oracle.ManagedDataAccess.Core。// app.config / web.config
<connectionStrings>
<add name="OracleConn"
connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.100)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)));User Id=myuser;Password=mypwd;Pooling=true;Min Pool Size=1;Max Pool Size=100;Connection Lifetime=120;"
providerName="Oracle.ManagedDataAccess.Client" />
</connectionStrings>
| 參數 | 說明 | 建議值 |
|---|---|---|
| Data Source | 易記名稱 (tnsnames.ora) 或完整 EZCONNECT 描述 | EZCONNECT 免維護 tnsnames.ora |
| User Id / Password | 認證帳密 | 從設定檔讀取,勿硬編碼 |
| Pooling | 啟用連線池 | true (生產環境必開) |
| Min Pool Size | 池最小連線數 | 1~5 |
| Max Pool Size | 池最大連線數 | 50~200 視負載調整 |
| Connection Lifetime | 連線存活秒數 (0=永久) | 120~300 定期回收避免殭屍連線 |
| Validate Connection | 取出池時驗證連線有效性 | true (犧牲微小效能換穩定) |
| Unicode | 啟用 Unicode 支援 | true (含中文資料必開) |
using System;
using System.Data;
using Oracle.ManagedDataAccess.Client;
using System.Configuration;
public static class OracleHelper
{
private static readonly string ConnStr = ConfigurationManager.ConnectionStrings["OracleConn"].ConnectionString;
// 執行查詢回傳 DataTable
public static DataTable ExecuteQuery(string sql, params OracleParameter[] parameters)
{
using (var conn = new OracleConnection(ConnStr))
using (var cmd = new OracleCommand(sql, conn))
{
if (parameters != null) cmd.Parameters.AddRange(parameters);
using (var adapter = new OracleDataAdapter(cmd))
{
var dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
// 執行非查詢 (INSERT/UPDATE/DELETE/存儲過程)
public static int ExecuteNonQuery(string sql, params OracleParameter[] parameters)
{
using (var conn = new OracleConnection(ConnStr))
using (var cmd = new OracleCommand(sql, conn))
{
if (parameters != null) cmd.Parameters.AddRange(parameters);
conn.Open();
return cmd.ExecuteNonQuery();
}
}
// 執行純量查詢
public static object ExecuteScalar(string sql, params OracleParameter[] parameters)
{
using (var conn = new OracleConnection(ConnStr))
using (var cmd = new OracleCommand(sql, conn))
{
if (parameters != null) cmd.Parameters.AddRange(parameters);
conn.Open();
return cmd.ExecuteScalar();
}
}
// 呼叫存儲過程回傳游標 (OracleRefCursor)
public static DataTable ExecuteProcCursor(string procName, params OracleParameter[] parameters)
{
using (var conn = new OracleConnection(ConnStr))
using (var cmd = new OracleCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null) cmd.Parameters.AddRange(parameters);
using (var adapter = new OracleDataAdapter(cmd))
{
var dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
}
public partial class LoginForm : Form
{
private void btnLogin_Click(object sender, EventArgs e)
{
// 動態建構連線字串 (實務建議從加密設定檔讀取)
var builder = new OracleConnectionStringBuilder
{
DataSource = txtDataSource.Text.Trim(), // EZCONNECT 字串
UserID = txtUser.Text.Trim(),
Password = txtPwd.Text,
Pooling = true
};
using (var conn = new OracleConnection(builder.ConnectionString))
{
try
{
conn.Open();
MessageBox.Show("連線成功!");
this.Hide();
new MainForm(builder.ConnectionString).Show();
}
catch (OracleException ex)
{
MessageBox.Show($"連線失敗: {ex.Message}\n錯誤碼: {ex.Number}");
}
}
}
}
public partial class MainForm : Form
{
private readonly string _connStr;
public MainForm(string connStr) { InitializeComponent(); _connStr = connStr; }
private void MainForm_Load(object sender, EventArgs e)
{
LoadUserData();
}
private void LoadUserData()
{
const string sql = "SELECT user_id, user_name, email, created_date FROM app_users WHERE status = :status ORDER BY created_date DESC";
var param = new OracleParameter("status", OracleDbType.Varchar2, "A", ParameterDirection.Input);
try
{
using (var conn = new OracleConnection(_connStr))
using (var cmd = new OracleCommand(sql, conn))
using (var adapter = new OracleDataAdapter(cmd))
{
cmd.Parameters.Add(param);
var dt = new DataTable();
adapter.Fill(dt);
dataGridView1.DataSource = dt;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
}
}
catch (Exception ex)
{
MessageBox.Show($"查詢失敗: {ex.Message}");
}
}
}
TNS_ADMIN 環境變數中。lsnrctl status)。sqlnet.ora 設定 SQLNET.ALLOWED_LOGON_VERSION_SERVER=11 或升級客戶端驅動。Unicode=True,資料庫字符集為 AL32UTF8,NLS_LANG 環境變數設為 TRADITIONAL CHINESE_TAIWAN.ZHT16MSWIN950 或 AMERICAN_AMERICA.AL32UTF8。using 區塊確保連線釋回池,調整 Max Pool Size 與資料庫 PROCESSES 參數。OpenAsync()、ExecuteReaderAsync() 避免阻塞 UI 執行緒。OracleCommand.ArrayBindCount 搭配參數陣列執行批次 INSERT/UPDATE,效能優於迴圈。OracleConnection 為 Scoped 服務,配合 IOptions<OracleSettings> 管理設定。採用 Oracle.ManagedDataAccess、EZCONNECT 連線字串、參數化查詢與連線池配置,能構建穩定、高效、可維護的 .NET-Oracle 資料存取層。嚴格遵循 using 模式管理連線生命週期,善用非同步 API 提升回應性,並建立完善的錯誤碼對應與監控機制,是企業級應用的關鍵成功因素。