![]() |
图 1: 在 Visual Studio.NET 中创建一个新工程 |
![]() |
图 2: 使用 New Project 对话框 |
您将需要为工程(我们使用 OtnWinApp)和解决方案(我们使用 OtnSamples)指定有意义的名称。 一个解决方案包含一个或多个工程。 当一个解决方案仅包含一个工程时,许多人对二者使用相同的名称。
添加引用
因为我们的工程必须与 Oracle 数据库连接,因此必须添加一个到包含我们选择的数据供应程序的 dll 的引用。 在 Solution Explorer 内,选择 References 节点,右键单击并选择 Add Reference。 或者,您可以转至菜单栏并选择 Project,然后选择 Add Reference。
![]() |
图 3: 添加引用 |
![]() |
图 4: 选择 ODP.NET 管理的数据供应程序 |
![]() |
图 5: 选择 Oracle Managed Provider 之后的解决方案浏览器 |
Imports System.Data ' VB.NET Imports Oracle.DataAccess.Client ' ODP.NET Oracle managed provider using System.Data; // C# using Oracle.DataAccess.Client; // ODP.NET Oracle managed provider import 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.NET string 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.NET OracleConnection conn = new OracleConnection(oradb); // C#
注意,通过将连接字符串传递给连接对象的构造器(该构造器进行了重载),连接字符串与连接对象建立关联。 构造函数的其他重载允许以下这些替代的语法:
Dim conn As New OracleConnection() ' VB.NET conn.ConnectionString = oradb OracleConnection conn = new OracleConnection(); // C# conn.ConnectionString = oradb;
在连接字符串与连接对象建立关联之后,使用 Open 方法来创建实际的连接。
conn.Open() ' VB.NET conn.Open(); // C#
我们将在稍后介绍错误处理。
Command 对象
Command 对象用于指定执行的 SQL 命令文本 — SQL 字符串或存储过程。 类似于 Connection 对象,它必须从完成其类的实例化,并且它拥有一个重载的构造函数。
Dim sql As String = "select dname from dept where deptno = 10" ' VB.NET Dim cmd As New OracleCommand(sql, conn) cmd.CommandType = CommandType.Text string 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.NET dr.Read() Label1.Text = dr.Item("dname") ' retrieve by column name Label1.Text = dr.Item(0) ' retrieve the first column in the select list Label1.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 运行时将尝试隐式地转换数据类型。 有时数据类型不兼容,则隐式转换将失败,并跳出一个异常警报。 但即使可以进行隐式转换,使用显式数据类型转换仍比用隐式数据类型转换好。 #p#分页标题#e#
到整型的显式转换显示如下:
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.NET conn.Dispose() ' VB.NET conn.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.NET Try conn.Open() Dim cmd As New OracleCommand cmd.Connection = conn cmd.CommandText = "select dname from dept where deptno = " + TextBox1.Text cmd.CommandType = CommandType.Text If dr.Read() Then Label1.Text = dr.Item("dname") ' or use dr.Item(0) End If Catch ex As Exception ' catches any error MessageBox.Show(ex.Message.ToString()) Finally conn.Dispose() End Try OracleConnection 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(); }
虽然这种方法将适当地捕获尝试从数据库中获取数据时发生的任何错误,但这种方法对用户却不友好。 例如,看看下面这条在数据库不可用时显示的消息。
![]() |
图 6: 捕获到一个 ORA-12545 错误,并向用户显示。 |
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 If Catch 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 错误消息显示如下:
![]() |
图 7: 针对 ORA-12545 错误的对用户友好的消息 |
Finally 代码将始终执行,而无论错误是否发生。 通过在 Finally 代码块中加入连接对象的 Close 或 Dispose 方法调用,在执行了 Try-Catch-Finally 代码段之后,数据库连接将始终关闭。 试图关闭没有打开的数据库连接不会导致错误。 例如,如果数据库不可用,数据库连接没有打开,那么 Finally 代码块将试图关闭不存在的连接。 执行多余的 Close 或 Dispose 是无效的。 只需将一条 Close 或 Dispose 方法放到 Finally 代码块中,将保证关闭连接。#p#分页标题#e#
利用 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.NET Label1.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 While while (dr.Read()) // C# { listBox1.Items.Add("The " + dr.GetString(1) + " department is in " + dr.GetString(2); }
上机操作 3(利用 DataReader 检索多列和多行)重点介绍了这些概念中的一部分。
总结
本文向您介绍了使用 VS.NET 编程语言访问 Oracle 数据库的过程。 您现在应该能够连接数据库并检索多列和多行。
评论 {{userinfo.comments}}
{{child.content}}
{{question.question}}
提交