Professional Documents
Culture Documents
NET Framework, many developers are hungry for information about the best
means of integrating .NET applications with Oracle—not only in terms of basic connectivity, but also in relationship to
effective and efficient application development using Visual Studio 2005 or 2008.
In this article, I'll explain the basic yet essential processes involved in building a .NET application that uses an Oracle
database, including:
How to add project references to support Oracle class libraries in your .NET project
How to create Oracle Database connection strings
How to work with Connection, Command, and DataReader objects
You will have the opportunity to apply what you have learned in three practice labs, ranging in difficulty from the
relatively simple to the more complex. The article's screenshots are taken from Visual Studio 2008, but the
experience is very similar in Visual Studio 2005.
For information and labs about how to secure your application, see my article " Securing a .NET Application on the
Oracle Database". (Also, see the OTN .NET Developer Center for technical articles covering a range of Oracle.NET
application lifecycle issues.)
Note that the free Oracle Developer Tools for Visual Studio, available for download from OTN, provides a Visual Studio
add-in that makes the development of .NET apps on Oracle much easier and more intuitive. That subject is beyond
our scope here, however.
Oracle, Microsoft, and third-party vendors all offer .NET data providers optimized for Oracle. Oracle and Microsoft
make their Oracle data providers available for free. (Microsoft's provider for the .NET Framework 2.0 is included in
the framework, but it still requires Oracle client software installation.) In this article, we will use of the Oracle Data
Provider for .NET (ODP.NET), which is included with the Oracle Database or as a separate download.
ODP.NET provides standard ADO.NET data access, while exposing Oracle database-specific features, such as XML
DB, data access performance optimizations, and Real Application Clusters connection pooling.
When ODP.NET and Oracle client software are installed, application development using Visual Studio can begin. It's
a good idea to confirm client connectivity before starting development. If you can connect to Oracle using Oracle
client software such as SQL*Plus on the same machine as Visual Studio, then you know that your Oracle client-side
software is properly installed and configured.
If you are new to Oracle, see the section "Installing .NET Products" in the Oracle Database 2 Day Developer's Guide
for background information regarding installing and configuring ODP.NET specifically, or to the Oracle Database
Documentation Library for general information about Oracle Database.
After starting Visual Studio, the first task is to create a project. You can either select File | New | Project as shown
below or click the New Project button located directly under File.
Figure 1 Creating a new project in Visual Studio 2008 Service Pack 1
A New Project dialog box appears. On the left side of the dialog box under Project Types, select the programming
language of your choice. In our example, "Visual Basic" was chosen. On the right side under Visual Studio installed
templates, choose a project template. To keep things simple, a "Windows Forms Application" is selected.
Figure 2 Using the New Project dialog
You'll want to specify meaningful names for the project name (we used OraWinApp) and the solution name (we used
OraWinApp). A solution contains one or more projects. When a solution contains only one project, many people use
the same name for both.
Adding a Reference
Because our project must connect to an Oracle database, it is necessary to add a reference to the ODP.NET DLL
containing the data provider of our choice. Within the Solution Explorer, select the project name, right click and select
Add Reference. Alternatively, you can go to the menu bar and select Project and then select Add Reference.
Figure 3 Adding a reference
ODP.NET is found under the Oracle.DataAccess component name. Select Oracle.DataAccess from the list, then
click OK to make the ODP.NET data provider known to your project.
By convention, these statements appear at or near the top of a code file, before the namespace or class declaration.
OraDb=
(DESCRIPTION=
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))
)
(CONNECT_DATA=
(SERVER=DEDICATED)
(SERVICE_NAME=ORCL)
)
)
The OraDb alias defines the database address connection information for the client. To use the OraDb alias defined
in the tnsnames.ora file shown above, you would use the following syntax:
Dim oradb As String = "Data Source=OraDb;User Id=scott;Password=tiger;" '
Visual Basic
// C#
string oradb = "Data Source=(DESCRIPTION="
+ "(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)
(PORT=1521)))"
+ "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));"
+ "User Id=scott;Password=tiger;";
As you can see above, the username and password are embedded in the connection string in clear text. This is the
simplest approach to creating a connection string. However, the clear text approach is undesirable from a security
perspective. In particular, you must understand that compiled .NET application code is only marginally more secure
than the clear text source code files. It is very easy to decompile .NET DLL and EXE files and view the original clear
text contents. (Encryption is in fact the appropriate solution, but that subject would be a quite lengthy digression from
our discussion here.)
Next, you must instantiate a connection object from the connection class. The connection string must be associated
with the connection object.
conn.Open(); // C#
We'll cover error handling later.
Command Object
The Command object is used to specify the SQL command text that is executed, either a SQL string or a stored
procedure. Similar to the Connection object, it must be instantiated from its class and it has an overloaded
constructor. In this sample, ODP.NET will perform a SQL query to return the department name (DNAME) from the
departments table (DEPT) where the department number (DEPTNO) is 10.
Dim sql As String = "select dname from dept where deptno = 10" ' Visual Basic
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text
label1.Text = dr.GetInt16("deptno").ToString(); // C#
You can explicitly cast scalar values as well as arrays.
conn.Close(); // C#
conn.Dispose(); // C#
You don't have to explicitly call Close or Dispose if you use VB's Using keyword or C#'s using keyword.
using (OracleConnection conn = new OracleConnection(oradb)) // C#
{
conn.Open();
OracleDataReader dr = cmd.ExecuteReader();
dr.Read();
label1.Text = dr.GetString(0);
}
In addition, OracleCommand includes a Dispose method; OracleDataReader includes a Close and Dispose
method. Closing and disposing .NET objects free up system resources, ensuring more efficient application
performance, which is especially important under high load conditions. You can experiment with some of the
concepts we've learned here in Lab 1 (Retrieving Data from the Database) and Lab 2 (Adding Interactivity).
Error Handling
When an error occurs, .NET applications should gracefully handle the error and inform the user with a meaningful
message. Try-Catch-Finally structured error handling is a part of .NET languages; here is a relatively minimalist
example of using the Try-Catch-Finally syntax:
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
' In a real application, put cleanup code here.
End Try
// C#
try
{
conn.Open();
if (dr.Read()) // C#
{
label1.Text = dr["dname"].ToString();
// or use dr.GetOracleString(0).ToString()
}
}
catch (Exception ex) // catches any error
{
MessageBox.Show(ex.Message.ToString());
}
finally
{
// In a real application, put cleanup code here.
}
Although this approach will gracefully capture any errors in attempting to get data from the database, it is not user
friendly. For example, look at the following message displayed when the database is unavailable:
An ORA-12545 is quite meaningful for an Oracle DBA or developer, but not for an end user. A better solution is to
add an additional Catch statement to trap for the most common database errors and provide user-friendly
messages.
Catch ex As OracleException ' catches only Oracle errors
Select Case ex.Number
Case 1
MessageBox.Show("Error attempting to insert duplicate data.")
Case 12545
MessageBox.Show("The database is unavailable.")
Case Else
MessageBox.Show("Database error: " + ex.Message.ToString())
End Select
Catch ex As Exception ' catches any error
MessageBox.Show(ex.Message.ToString())
The Finally code block is always executed regardless of whether or not an error occurred. It is where cleanup code
belongs. If you don't use Using or using, you should dispose your connection and other objects in the Finally
code block.
Here is a code snippet that concatenates the DNAME and LOC columns from the previous query:
while (dr.Read()) // C#
{
listBox1.Items.Add("The " + dr["dname"].ToString() + " department is in "
+
dr["loc"].ToString());
}
Lab 3 (Retrieve Multiple Columns and Rows with an OracleDataReader) highlights some of these concepts.
Figure 8 Change from Any CPU to x86 when building on a 64-bit platform
Conclusion
This article has introduced you to the process of accessing Oracle databases using .NET programming languages.
You should now have the capability to connect to the database and retrieve multiple columns and rows.
1. Continue by adding a button control and a label control to the Windows form. Be sure to leave room above
the controls to allow additions that will be made in Lab 2.
Figure 9 Lab 1 form with button and label controls
2. Add code to retrieve data from the Oracle database and display the results on the form. Put the code in a
click event handler for the button. The easiest way to get started with this task is to double click the button
because it will create a stub for the event handler.
Figure 10 Click event handler stub
3. Add Visual Basic Imports statements before the Public Class declaration or C# using statements before the
namespace declaration.
4. Imports Oracle.DataAccess.Client ' Visual Basic, ODP.NET Oracle managed
provider
5.
6. using Oracle.DataAccess.Client; // C#, ODP.NET Oracle managed provider
7. Add the Visual Basic version of the click event handler code between the Private Sub and End Sub
statements (be sure to replace ORASRVR with your server's host name):
8. Dim oradb As String = "Data Source=(DESCRIPTION=(ADDRESS_LIST=" _
9. + "(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)
(PORT=1521)))" _
10. + "(CONNECT_DATA=(SERVER=DEDICATED)
(SERVICE_NAME=ORCL)));" _
11. + "User Id=scott;Password=tiger;"
12.
13. Dim conn As New OracleConnection(oradb) ' Visual Basic
14. conn.Open()
15.
16. Dim cmd As New OracleCommand
17. cmd.Connection = conn
18. cmd.CommandText = "select dname from dept where deptno = 10"
19. cmd.CommandType = CommandType.Text
20.
21. Dim dr As OracleDataReader = cmd.ExecuteReader()
22. dr.Read() ' replace this statement in next lab
23. Label1.Text = dr.Item("dname") ' or dr.Item(0), remove in next lab
24.
25. dr.Dispose()
26. cmd.Dispose()
27. conn.Dispose()
Add the following C# code to the click event handler between the { and } curly braces for the button's click
event handler (be sure to replace ORASRVR with your server's host name):
OracleDataReader dr = cmd.ExecuteReader();
dr.Read(); // replace this statement in next lab
label1.Text = dr["dname"].ToString(); // remove in next lab
dr.Dispose();
cmd.Dispose();
conn.Dispose();
28. Run the application. Click the button. You should see the following:
Figure 11 Data successfully retrieved.
1. Add a textbox control and another label control to the form as shown below. Set the text property of the
Label2 control to Enter Deptno: and make sure that the Text property of TextBox1 isn't set to
anything.
Figure 12 Lab 2 form with button and label controls
3. Run the application. Test the application by entering 10 for the DEPTNO. Retest the application by entering
an invalid DEPTNO (e.g., 50). The application will abort.
Figure 13 An unhandled exception
4. Modify your code to prevent an error when an invalid DEPTNO is entered. Recall that the ExecuteReader
method actually returns an object. Replace the line containing dr.Read with all of the following statements.
if (dr.Read()) // C#
{
label1.Text = dr["dname"].ToString();;
}
else
{
label1.Text = "deptno not found";
}
Test the application by entering a DEPTNO that does not exist. Now the application no longer aborts. Enter
the letter A instead of a number and click the button. The application aborts. Clearly, our application needs a
better approach to handling errors.
Although it could be argued that the application should not allow the user to make invalid inputs that would
cause an error, ultimately the application must have robust error handling added. Not all errors are
preventable, so error handling must be implemented.
1. Add a ListBox control to the form. Resize the control to fill most of the width of the form as shown below.
cmd.CommandText = "select deptno, dname, loc from dept" ' Visual Basic
cmd.CommandText = "select deptno, dname, loc from dept"; // C#
3. The query results will be read in a while loop and will populate the ListBox control. Modify your Visual
Basic code to look like this:
dr.Dispose()
cmd.Dispose()
conn.Dispose()
Modify your C# code to look like this:
string oradb = "Data Source=(DESCRIPTION=(ADDRESS_LIST="
+ "(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))"
+ "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));"
+ "User Id=scott;Password=tiger;";
OracleDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
listBox1.Items.Add("The " + dr["dname"].ToString() +
" department is in " + dr["loc"].ToString());
}
dr.Dispose();
cmd.Dispose();
conn.Dispose();
4. Run the application. The ListBox should be populated with all of the department names and locations from
the DEPT table. The code downloads have error handling implemented.
John Paul Cook [ johnpaulcook@email.com] is a database and .NET consultant based in Houston. He is the author of
numerous articles on .NET, Oracle, and virtualization and has been developing relational database applications since
1986. His current interests include Visual Studio 2008 and Oracle Database 11g. He is an Oracle certified DBA and a
Microsoft Most Valuable Professional.