.NET 應用連接 Oracle 需要 Managed Data Provider。雖然 Microsoft 內建 System.Data.OleDb 與 System.Data.Odbc 通用提供者,但針對特定資料庫優化的原生提供者(Oracle ODP.NET、Microsoft OracleClient、第三方 Core Lab 等)在效能、功能支援、型別對應上具備決定性優勢。本文以 Oracle Data Provider for .NET (ODP.NET) 為例,示範 Visual Studio .NET 開發全流程。
在 VS.NET 機器上安裝 Oracle Client 並設定 tnsnames.ora 後,用 SQL*Plus 測試連線:
sqlplus scott/tiger@OraDb
-- 成功連線代表客戶端配置正確,可進行開發
File > New > Project > Visual Basic Projects > Windows Application,專案名 OtnWinApp,方案名 OtnSamplesReferences > Add Reference,選擇 Oracle.DataAccess.dll(通常在 %ORACLE_HOME%\odp.net\bin\2.x)Imports System.Data
Imports Oracle.DataAccess.Client ' ODP.NET 命名空間
' tnsnames.ora 定義:
' OraDb = (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)))
Dim oradb As String = "Data Source=OraDb;User Id=scott;Password=tiger;"
Dim oradb As String = "Data Source=(DESCRIPTION=" & _
"(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)))" & _
"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" & _
"User Id=scott;Password=tiger;"
連接字串含明文密碼,編譯後的 .NET 組件易被反編譯(ILDASM、Reflector)。生產環境應採用:
aspnet_regiis -pef connectionStrings)Dim conn As New OracleConnection(oradb)
Dim cmd As New OracleCommand()
cmd.Connection = conn
cmd.CommandText = "SELECT DName FROM Dept WHERE DeptNo = :deptno"
cmd.CommandType = CommandType.Text
cmd.Parameters.Add("deptno", OracleDbType.Int32).Value = 10
Try
conn.Open()
Dim dname As String = CStr(cmd.ExecuteScalar()) -- 單一值
Label1.Text = dname
Catch ex As OracleException
HandleOracleError(ex)
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
conn.Dispose() -- 確保關閉,含連線池歸還
End Try
Dim sql As String = "SELECT DeptNo, DName, Loc FROM Dept"
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text
conn.Open()
Dim dr As OracleDataReader = cmd.ExecuteReader()
While dr.Read()
' 三種存取方式:
' 1. 索引器(欄位名/序號):dr("DName") 或 dr(1)
' 2. 強型別 Get 方法:dr.GetString(1), dr.GetInt32(0)
' 3. GetValue/GetOracleValue 取得 Object/Oracle 型別
ListBox1.Items.Add("Dept " & dr.GetInt32(0) & ": " & dr.GetString(1) & " @ " & dr.GetString(2))
End While
dr.Close()
關鍵差異:VB.NET 支援隱含型別轉換,C# 必須顯式轉換(dr.GetInt32(0).ToString())。
cmd.CommandText = "SELECT * FROM Emp WHERE EmpNo = :empno AND DeptNo = :deptno"
cmd.Parameters.Clear()
cmd.Parameters.Add("empno", OracleDbType.Int32).Value = txtEmpNo.Text
cmd.Parameters.Add("deptno", OracleDbType.Int32).Value = txtDeptNo.Text
' 參數綁定順序不影響,但建議與 SQL 順序一致以利閱讀
Try
conn.Open()
' ... 執行命令 ...
Catch oraEx As OracleException
' 針對 Oracle 錯誤代碼給予友善訊息
Select Case oraEx.Number
Case 1 : MessageBox.Show("資料重複(唯一鍵衝突)")
Case 12545 : MessageBox.Show("資料庫服務不可用,請稍後再試")
Case 20001 : MessageBox.Show("自訂業務錯誤:" & oraEx.Message)
Case Else : MessageBox.Show("資料庫錯誤:" & oraEx.Message)
End Select
Catch ex As Exception
MessageBox.Show("系統錯誤:" & ex.Message)
Finally
If conn.State = ConnectionState.Open Then conn.Close()
conn.Dispose()
End Try
原則:Catch 區塊按「特殊→一般」排序;Finally 確保資源釋放;嘗試關閉未開啟的連線不會拋出例外。
using (OracleConnection conn = new OracleConnection(oradb))
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("SELECT DName FROM Dept WHERE DeptNo = 10", conn))
using (OracleDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
label1.Text = dr.GetString(0);
}
} // 區塊結束自動呼叫 Dispose(),等同 conn.Close()
Dim da As New OracleDataAdapter("SELECT * FROM Dept", conn)
Dim ds As New DataSet()
da.Fill(ds, "DeptTable")
' ds.Tables("DeptTable") 現可繫結至 DataGrid、離線修改、批次更新
' 更新時需設定 InsertCommand/UpdateCommand/DeleteCommand 或使用 OracleCommandBuilder
Oracle.DataAccess.dll 正確版本(x86/x64 與 IIS/應用程式池一致)