在Oracle上構建 .NET 應用程式

來源:互聯網
上載者:User
oracle|程式 瞭解構建使用 Oracle 資料庫的 .NET 應用程式所涉及到的基本但不可或缺的過程

本文涉及的下載

· 範例程式碼

· Oracle Data Provider for .NET (ODP.NET)

隨著 Microsoft 的 .NET 架構的逐漸流行,許多開發人員迫切想瞭解關於將 .NET 應用程式與 Oracle 整合的最好的方式的資訊 — 不僅在基本的連通性方面,還包括與使用 Visual Studio.NET (VS.NET) 進行有效應用程式開發的關係。

在本文中,我將說明構建使用 Oracle 資料庫的 .NET 應用程式所涉及到的基本但不可或缺的過程,包括:

如何添加工程引用,以在您的 .NET 工程中支援 Oracle 類

如何建立 Oracle 資料庫連接字串

如何使用 Connection、Command 和 DataReader 對象。

您將有機會應用您在三個上機操作實踐中學到的內容,難度範圍從比較容易到更複雜。

.NET Data Provider

除了基本的 Oracle 用戶端連通性軟體,.NET 應用程式還需要使用稱為 managed data provider(其中 "managed" 指的是代碼由 .NET 架構管理)的工具。 資料供應程式是 .NET 應用程式代碼和 Oracle 用戶端連通性軟體之間的層。 在幾乎所有情況下,最優的效能都是通過使用為特定資料庫平台最佳化了的供應程式而不是一般的 .NET OLE DB 資料供應程式實現的。



Oracle、Microsoft 和第三方供應商都提供了針對 Oracle 產品進行了最佳化的資料供應程式。 Oracle 和 Microsoft 免費提供其 Oracle 資料供應程式。 (Microsoft 為 .NET 架構的 1.1 版提供的供應程式包含在該架構中,不需要單獨下載或安裝。) 一些第三方資料供應程式支援 Oracle 的較早的版本,或者不需要安裝 Oracle 用戶端軟體。 在本文中,我們假設使用 Oracle Data Provider for .NET (ODP.NET),並單獨提供下載。



當安裝了 ODP.NET 和所有要求的 Oracle 用戶端連通性軟體時,就可以開始使用 Visual Studio.NET 進行應用程式開發了。 在開始開發前,請先確認用戶端連通性。 如果您在 VS.NET 所在的電腦上使用 SQL*Plus 能夠與 Oracle 串連,那麼證明您已經正確地安裝和配置了 Oracle 用戶端軟體。



如果您剛接觸 Oracle,那麼請參閱 Oracle Data Provider for .NET 開發人員指南 10g 版本 1 (10.1) 中的“與 Oracle 資料庫連接”部分,以瞭解 ODP.NET 的背景資訊,或參閱 Oracle 資料庫管理員指南 10g 版本 1 (10.1),以瞭解關於管理 Oracle 資料庫的通用資訊。 您還可以查閱“使用 ODP.NET 與 Oracle 資料庫連接”範例程式碼“方法”文檔。



在 Visual Studio.NET 中建立工程



在啟動 VS.NET 之後,第一個任務是建立一個工程。 您可以單擊 New Project 按鈕或選擇 File | New | Project...。



出現一個 New Project 對話方塊。 在對話方塊左側的 Project Types 下,選擇您的程式設計語言。 在這個例子中,我們選擇 VB.NET。 在右側的 Templates 下,選擇一個工程模板。 為簡單起見,這裡選擇 Windows Application。



您將需要為工程(我們使用 OtnWinApp)和解決方案(我們使用 OtnSamples)指定有意義的名稱。 一個方案套件含一個或多個工程。 當一個解決方案僅包含一個工程時,許多人對二者使用相同的名稱。



添加引用



因為我們的工程必須與 Oracle 資料庫連接,因此必須添加一個到包含我們選擇的資料供應程式的 dll 的引用。 在 Solution Explorer 內,選擇 References 節點,按右鍵並選擇 Add Reference。 或者,您可以轉至功能表列並選擇 Project,然後選擇 Add Reference。



出現 Add Reference 對話方塊。



從列表中選擇 Oracle.DataAccess.dll,然後單擊 Select 按鈕,最後單擊 OK 按鈕,使您的工程能夠找到 ODP.NET 資料供應程式。



VB.NET/C# 語句



在添加引用之後,標準的做法是要添加 VB.NET Imports 語句、C# using 語句或 J# import 語句。 從技術上說這些語句不是必要的,但是使用它們可以讓您不需用冗長且完整名稱來引用資料庫物件。



按照慣例,這些語句出現在代碼檔案的頂部或頂部附近,在命名空間或類聲明之前。



Imports System.Data ' VB.NETImports Oracle.DataAccess.Client ' ODP.NET Oracle managed providerusing System.Data; // C#using Oracle.DataAccess.Client; // ODP.NET Oracle managed providerimport System.Data.*; // J#import Oracle.DataAccess.Client; // ODP.NET Oracle managed provider





連接字串和對象



Oracle 連接字串和 Oracle 名稱解析是不可分的。 假定我們在 tnsnames.ora 檔案中定義了一個資料庫別名 OraDb,如下:



OraDb= (DESCRIPTION= (ADDRESS_LIST= (ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)) ) (CONNECT_DATA= (SERVER=DEDICATED) (SERVICE_NAME=ORCL) ) )

要使用上面所述的在 tnsnames.ora 檔案中定義的 OraDb 別名,您需要使用以下文法:

Dim oradb As String = "Data Source=OraDb;User Id=scott;Password=tiger;" ' VB.NETstring oradb = "Data Source=OraDb;User Id=scott;Password=tiger;"; // C#

不過,您可以修改連接字串,這樣就不需用 tnsnames.ora 檔案。 只需用在 tnsnames.ora 檔案中定義別名的語句替換別名即可。

' VB.NET 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;"string oradb = "Data Source=(DESCRIPTION=" // C# + "(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)))" + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" + "User Id=scott;Password=tiger;";

正如您在上面看到的那樣,使用者名稱和口令是以不加密的文本形式嵌入到連接字串中的。 這是建立連接字串的最簡單的方法。 然而,從安全的角度而言不加密文本的方法是不可取的。 而且,您需要瞭解編譯的 .NET 應用程式代碼僅比不加密文本形式的原始碼檔案稍微安全一點。 可以非常簡便的反編譯 .NET dll 和 exe 檔案,進而查看原始的不加密文本形式的內容。 (加密實際上是正確的解決方案,但這個主題與我們這裡的討論相差太遠。)

接下來,您必須從串連類中完成一個連線物件的執行個體化。 連接字串必須與連線物件關聯。



Dim conn As New OracleConnection(oradb) ' VB.NETOracleConnection conn = new OracleConnection(oradb); // C#

注意,通過將連接字串傳遞給連線物件的構造器(該構造器進行了重載),連接字串與連線物件建立關聯。 建構函式的其他重載允許以下這些替代的文法:

Dim conn As New OracleConnection() ' VB.NETconn.ConnectionString = oradbOracleConnection conn = new OracleConnection(); // C#conn.ConnectionString = oradb;

在連接字串與連線物件建立關聯之後,使用 Open 方法來建立實際的串連。

conn.Open() ' VB.NETconn.Open(); // C#

我們將在稍後介紹錯誤處理。



Command 對象



Command 對象用於指定執行的 SQL 命令文本 — SQL 字串或預存程序。 類似於 Connection 對象,它必須從完成其類的執行個體化,並且它擁有一個重載的建構函式。



Dim sql As String = "select dname from dept where deptno = 10" ' VB.NETDim cmd As New OracleCommand(sql, conn)cmd.CommandType = CommandType.Textstring sql = "select dname from dept where deptno = 10"; // C#OracleCommand cmd = new OracleCommand(sql, conn);cmd.CommandType = CommandType.Text;

不同的重載,文法的結構稍微有點不同。 Command 對象有用於執行命令文本的方法。 不同的方法適用於不同類型的 SQL 命令。





檢索標量值





從資料庫中檢索資料可以通過執行個體化一個 DataReader 對象並使用 ExecuteReader 方法(它返回一個 OracleDataReader 對象)來實現。 通過將列名稱或以零為基數的列序號傳遞給項屬性 B.NET 開發人員可以訪問返回的資料。 另一種選擇是使用存取程式類型方法來返回列資料。



Dim dr As OracleDataReader = cmd.ExecuteReader() ' VB.NETdr.Read()Label1.Text = dr.Item("dname") ' retrieve by column nameLabel1.Text = dr.Item(0) ' retrieve the first column in the select listLabel1.Text = dr.GetString(0) ' retrieve the first column in the select list

C# 開發人員必須使用存取器方法來檢索資料。 有適當類型的存取程式用於返回 .NET 本機資料類型,其他的存取程式用於返回本地 Oracle 資料類型。 以零為基數的序號被傳遞給存取程式,以指定返回哪一列。

OracleDataReader dr = cmd.ExecuteReader(); // C#dr.Read();label1.Text = dr.GetString(0); // C# retrieve the first column in the select list

在這個簡化的例子中,dname 的傳回值是一個字串,它用來設定標籤控制項的文本的屬性值(也是一個字串)。 但如果檢索的是 deptno,而不是字串,那麼將出現資料類型不匹配的情況。 當來源資料類型與目標資料類型不匹配時,.NET 運行時將嘗試隱式地轉換資料類型。 有時資料類型不相容,則隱式轉換將失敗,並跳出一個異常警報。 但即使可以進行隱式轉換,使用顯式資料類型轉換仍比用隱式資料類型轉換好。

到整型的顯式轉換顯示如下:



Label1.Text = CStr(dr.Item("deptno")) ' VB.NET integer to string cast

在隱式轉換上,C# 的容錯能力不如 VB.NET。 您必須自己執行顯式轉換:

string deptno = dr.GetInt16("deptno").ToString(); // C#

您可以顯式地轉換標量值以及數組。



關閉並清除



可以調用連線物件的 Close 方法或 Dispose 方法來關閉到資料庫的串連。 Dispose 方法調用 Close 方法。



conn.Close() ' VB.NETconn.Dispose() ' VB.NETconn.Close(); // C#conn.Dispose(); // C#

作為可選項,C# 提供了一種在串連超出範圍時自動清除串連的特殊文法。 使用 using 關鍵字可啟用這一特性。

using (OracleConnection conn = new OracleConnection(oradb)){conn.Open();OracleCommand cmd = new OracleCommand(); cmd.Connection = conn; cmd.CommandText = "select dname from dept where deptno = 10";cmd.CommandType = CommandType.Text; OracleDataReader dr = cmd.ExecuteReader(); dr.Read(); label1.Text = dr.GetString(0);}

您可以實驗在上機操作 1(從資料庫中檢索資料)和上機操作 2(增加互動性)中學到的一些概念。



錯誤處理



Try-Catch-Finally 結構的錯誤處理是 .NET 語言的一部分。 下面是使用 Try-Catch-Finally 文法的一個相對最小的例子:



Dim conn As New OracleConnection(oradb) ' VB.NETTry conn.Open() Dim cmd As New OracleCommand cmd.Connection = conn cmd.CommandText = "select dname from dept where deptno = " + TextBox1.Textcmd.CommandType = CommandType.Text If dr.Read() Then Label1.Text = dr.Item("dname") ' or use dr.Item(0) End IfCatch ex As Exception ' catches any error MessageBox.Show(ex.Message.ToString())Finally conn.Dispose()End TryOracleConnection conn = new OracleConnection(oradb); // C#try{conn.Open();OracleCommand cmd = new OracleCommand(); cmd.Connection = conn; cmd.CommandText = "select dname from dept where deptno = " + textBox1.Text;cmd.CommandType = CommandType.Text; if (dr.Read()) // C# { label1.Text = dr.GetString(0); }}catch (Exception ex) // catches any error{ MessageBox.Show(ex.Message.ToString());}finally{ conn.Dispose();}

雖然這種方法將適當地捕獲嘗試從資料庫中擷取資料時發生的任何錯誤,但這種方法對使用者卻不友好。



Oracle DBA 或開發人員很清楚 ORA-12545 的意義,但是終端使用者不清楚。 一種更好的解決方案是添加一條額外的 Catch 語句來捕獲最常見的資料庫錯誤並顯示對方便使用的訊息。



Catch ex As OracleException ' catches only Oracle errors If InStr(1, ex.Message.ToString(), "ORA-1:", CompareMethod.Text) Then MessageBox.Show("Error attempting to insert duplicate data.") ElseIf InStr(1, ex.Message.ToString(), "ORA-12545:", CompareMethod.Text) Then MessageBox.Show("The database is unavailable.") Else MessageBox.Show("Database error: " + ex.Message.ToString()) End IfCatch ex As Exception ' catches any error MessageBox.Show(ex.Message.ToString())catch (OracleException ex) // catches only Oracle errors{ switch (ex.Number) {case 1: MessageBox.Show("Error attempting to insert duplicate data."); break; case 12545: MessageBox.Show("The database is unavailable."); break; default: MessageBox.Show("Database error:" + ex.Message.ToString()); break; }}catch (Exception ex) // catches any error{ MessageBox.Show(ex.Message.ToString());}

注意上面的程式碼範例中的兩條 Catch 語句。 如果沒有捕獲到任何 Oracle 錯誤,那麼將跳過第一條 Catch 語句分支,讓第二條 Catch 語句來捕獲其他任何類型的錯誤。 在代碼中,應該根據從特殊到一般的順序對 Catch 語句排序。 在實施了對方便使用的異常處理代碼之後,ORA-12545 錯誤訊息



Finally 代碼將始終執行,而無論錯誤是否發生。 通過在 Finally 代碼塊中加入連線物件的 Close 或 Dispose 方法調用,在執行了 Try-Catch-Finally 程式碼片段之後,資料庫連接將始終關閉。 試圖關閉沒有開啟的資料庫連接不會導致錯誤。 例如,如果資料庫不可用,資料庫連接沒有開啟,那麼 Finally 代碼塊將試圖關閉不存在的串連。 執行多餘的 Close 或 Dispose 是無效的。 只需將一條 Close 或 Dispose 方法放到 Finally 代碼塊中,將保證關閉串連。



利用 DataReader 檢索多個值



到目前為止,我們的樣本僅說明了如何檢索單個值。 DataReader 可以檢索多列和多行的值。 首先進行多行、單列的查詢:



select deptno, dname, loc from dept where deptno = 10

要擷取列的值,可以使用以零為基數的序號或列名。 序號與查詢中的順序相關。 因而,可以在 VB.NET 中通過使用 dr.Item(2) 或 dr.Item("loc") 來查詢 loc 列的值。



下面是將 dname 和來自上一查詢的 loc 列串聯起來的程式碼片段:



Label1.Text = "The " + dr.Item(1) + " department is in " + dr.Item("loc") ' VB.NETLabel1.Text = "The " + dr.GetString(1) + " department is in " + dr.GetString(2); // C#

現在我們進行返回多行的查詢:

select deptno, dname, loc from dept

要處理從 DataReader 中返回的多行,需要某種類型的迴圈結構。 此外,需要一個可以顯示多行的控制項。 DataReader 是一個僅正向的唯讀遊標,因此不能將其與可更新或完全可滾動的控制項(如 Windows Forms DataGrid 控制項)捆綁在一起。 DataReader 與 ListBox 控制項相容,如以下程式碼片段所示:

While dr.Read() ' VB.NET ListBox1.Items.Add("The " + dr.Item(1) + " department is in " + dr.Item("loc")) End Whilewhile (dr.Read()) // C#{ listBox1.Items.Add("The " + dr.GetString(1) + " department is in " + dr.GetString(2);}

上機操作 3(利用 DataReader 檢索多列和多行)重點介紹了這些概念中的一部分。

總結



本文向您介紹了使用 VS.NET 程式設計語言訪問 Oracle 資料庫的過程。 您現在應該能夠串連資料庫並檢索多列和多行。





John Paul Cook (johnpaulcook@email.com) 是居住在休斯頓的一位元據庫和 .NET 顧問。 他撰寫了許多關於 .NET、Oracle 和其他主題的文章,並從 1986 年以來一直開發關聯式資料庫應用程式。他目前的興趣包括 Visual Studio 2005 和 Oracle 10g。 他是 Oracle 認證 DBA 和 Microsoft MCSD for .NET。





上機操作 1: 從資料庫中檢索資料



首先向 Windows 表單添加一個按鈕控制項和一個標籤控制項。 務必在這些控制項上方保留空間,以便在上機操作 2 中添加控制項。











添加代碼,它們用於從 Oracle 資料庫中檢索資料並在表單上顯示結果。 將代碼放在按鈕的單擊事件處理常式中。 開始這項任務的最容易的方式是雙擊該按鈕,因為它將為事件處理常式建立一個 stub。











在 Public Class 聲明之前添加 VB.NET Imports 語句,或在命名空間聲明之前添加 C# using 語句。

Imports System.Data ' VB.NETImports Oracle.DataAccess.Client ' ODP.NET Oracle managed providerusing System.Data; // C#using Oracle.DataAccess.Client; // ODP.NET Oracle managed provider

在 Private Sub 和 End Sub 語句之間添加 VB.NET 版本 事件語句代碼(確保用您的伺服器的主機名稱替代 OTNSRVR):

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;"Dim conn As New OracleConnection(oradb) ' VB.NETconn.Open()Dim cmd As New OracleCommandcmd.Connection = conncmd.CommandText = "select dname from dept where deptno = 10"cmd.CommandType = CommandType.TextDim dr As OracleDataReader = cmd.ExecuteReader()dr.Read()Label1.Text = dr.Item("dname") ' or dr.Item(0)conn.Dispose()

將以下 C# 代碼添加到按鈕的單擊事件處理常式中的括弧 { 和 } 之間,並確保用您的伺服器的主機名稱替代 OTNSRVR:

string oradb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=" + "(ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)))" + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" + "User Id=scott;Password=tiger;";OracleConnection conn = new OracleConnection(oradb); // C#conn.Open();OracleCommand cmd = new OracleCommand();cmd.Connection = conn;cmd.CommandText = "select dname from dept where deptno = 10";cmd.CommandType = CommandType.Text;OracleDataReader dr = cmd.ExecuteReader();dr.Read();label1.Text = dr.GetString(0);conn.Dispose();

運行應用程式。 單擊按鈕。 您將看到以下內容:





上機操作 2: 增加互動性





現在在代碼中實施了資料庫訪問的基礎,下一步是為應用程式增加互動性。 可以添加一個文字框來接收使用者輸入的部門號碼 (deptno),而不是運行硬式編碼查詢。



向表單中添加一個文字框控制項和另一個標籤控制項: 將 Label2 控制項的文字屬性設為 Enter Deptno: 並確保沒有將 TextBox1 的 Text 屬性設為任何東西。





修改定義選擇字串的代碼:

cmd.CommandText = "select dname from dept where deptno = " + TextBox1.Text 'VB.NETcmd.CommandText = "select dname from dept where deptno = " + textBox1.Text; // C#

運行應用程式。 在 deptno 輸入 10,測試應用程式。 輸入一個無效的 deptno,重新測試應用程式。 應用程式將退出。



修改代碼以防止在輸入無效的 deptno 時出現錯誤。 讓我們回顧一下,ExecuteReader 方法實際返回一個對象。

If dr.Read() Then ' VB.NET Label1.Text = dr.Item("dname")Else Label1.Text = "deptno not found"End Ifif (dr.Read()) // C#{ label1.Text = dr.Item("dname");}Else{ label1.Text = "deptno not found";}

輸入不存在的 deptno 數字,測試應用程式。 現在應用程式不再退出。 輸入字母 A 代替數字,然後單擊按鈕。 應用程式退出。 很明顯,我們的應用程式需要更好的方法以處理錯誤。

可能有人會指出,應用程式應當不充許使用者進行將導致錯誤的無效輸入,但最終應用程式必須添加強健的錯誤處理功能。 不是所有的錯誤都是可預防的,因此必須實施錯誤處理。





上機操作 3: 利用 DataReader 檢索多行和多列

現在檢索了單個值,下一步就是利用 DataReader 檢索多行和多列。 添加一個 ListBox 控制項到表單中,以顯示結果。



添加一個 ListBox 控制項到表單中。 重新調整控制項的大小,以填滿表單的大部分寬度









從查詢中刪除 where 子句,並添加以下列:

cmd.CommandText = "select deptno, dname, loc from dept" ' VB.NETcmd.CommandText = "select deptno, dname, loc from dept"; // C#

修改 VB.NET 代碼,最終結果如下:

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;"Dim conn As New OracleConnection(oradb) ' VB.NETconn.Open()Dim cmd As New OracleCommandcmd.Connection = conncmd.CommandText = "select deptno, dname, loc from dept" cmd.CommandType = CommandType.TextDim dr As OracleDataReader = cmd.ExecuteReader()While dr.Read() ListBox1.Items.Add("The " + dr.Item(1) + _" department is in " + dr.Item("loc"))End Whileconn.Dispose()

修改您的 C# 代碼,最終結果如下:

string oradb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=" + "(ADDRESS=(PROTOCOL=TCP)(HOST=OTNSRVR)(PORT=1521)))" + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" + "User Id=scott;Password=tiger;";OracleConnection conn = new OracleConnection(oradb); // C#conn.Open();OracleCommand cmd = new OracleCommand();cmd.Connection = conn;cmd.CommandText = "select dname from dept where deptno = 10";cmd.CommandType = CommandType.Text;OracleDataReader dr = cmd.ExecuteReader();while (dr.Read()){ ListBox1.Items.Add("The " + dr.Item(1) + " department is in " + dr.GetString(0));}conn.Dispose();

提供代碼下載中已經實施了錯誤處理。

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。