MSDN Documentation

Data Access with ADO.NET and Oracle

This document provides a comprehensive guide to accessing Oracle databases using ADO.NET in your .NET applications. ADO.NET offers a powerful and flexible framework for database connectivity, and with the appropriate Oracle provider, you can leverage its capabilities to interact with Oracle data sources efficiently.

Introduction to Oracle Data Provider for .NET (ODP.NET)

Microsoft's ADO.NET is designed to be extensible, allowing for the integration of various data sources through data providers. For Oracle databases, the recommended and most performant provider is the Oracle Data Provider for .NET (ODP.NET), developed by Oracle Corporation. ODP.NET provides a set of classes that mirror the ADO.NET architecture but are optimized for Oracle.

Key Components of ODP.NET

  • OracleConnection: Establishes a connection to an Oracle database.
  • OracleCommand: Represents a Transact-SQL statement or stored procedure to execute against an Oracle data source.
  • OracleDataReader: Provides a way to read a forward-only stream of rows from an Oracle data source.
  • OracleDataAdapter: Used to fill a DataSet and to automatically resolve changes to data in a DataSet with the data source.
  • OracleParameter: Represents a parameter of an Oracle Command.

Setting Up ODP.NET

Before you can use ODP.NET, you need to install it. ODP.NET is typically included with Oracle client installations or can be downloaded separately from Oracle's website. Ensure you install the correct version of ODP.NET that matches your Oracle database and .NET Framework/Core versions.

After installation, you will need to reference the appropriate ODP.NET assembly in your project (e.g., Oracle.ManagedDataAccess.dll for the managed driver, or assemblies from the Oracle Data Access Components (ODAC) installation for the unmanaged driver).

Important: For most modern .NET applications, the Oracle.ManagedDataAccess NuGet package is the recommended choice as it's a pure .NET assembly, simplifying deployment and removing the dependency on the Oracle client installation.

Connecting to an Oracle Database

Establishing a connection is the first step in data access. The OracleConnection object uses a connection string to specify the details required to connect to the database.

Connection String Properties

A typical ODP.NET connection string includes properties such as:

  • Data Source: The service name or TNS entry of the Oracle database.
  • User ID: The username for connecting to the database.
  • Password: The password for the specified user.
  • Connection Pooling: Often enabled by default, enhancing performance.

Example Connection Code (C#)


using Oracle.ManagedDataAccess.Client;
using System;

public class OracleConnectionExample
{
    public static void Connect()
    {
        string connectionString = "Data Source=XE;User ID=system;Password=your_password;";
        using (OracleConnection connection = new OracleConnection(connectionString))
        {
            try
            {
                connection.Open();
                Console.WriteLine("Successfully connected to Oracle!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error connecting to Oracle: " + ex.Message);
            }
        }
    }
}
                

Executing SQL Commands

Once a connection is established, you can execute SQL commands using the OracleCommand object.

Executing a Query and Reading Data

The OracleDataReader is efficient for retrieving query results when you need to process rows one by one.


using Oracle.ManagedDataAccess.Client;
using System;
using System.Data;

public class OracleQueryExample
{
    public static void ReadData(string connectionString)
    {
        string sql = "SELECT employee_id, first_name, last_name FROM employees WHERE department_id = :dept_id";

        using (OracleConnection connection = new OracleConnection(connectionString))
        {
            using (OracleCommand command = new OracleCommand(sql, connection))
            {
                // Use OracleDbType for parameters
                command.Parameters.Add(new OracleParameter("dept_id", OracleDbType.Int32, 10, ParameterDirection.Input) { Value = 90 });

                try
                {
                    connection.Open();
                    using (OracleDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine($"ID: {reader["employee_id"]}, Name: {reader["first_name"]} {reader["last_name"]}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error executing query: " + ex.Message);
                }
            }
        }
    }
}
                

Executing Non-Query Commands (INSERT, UPDATE, DELETE)

For commands that do not return a result set, such as INSERT, UPDATE, or DELETE, use ExecuteNonQuery().


using Oracle.ManagedDataAccess.Client;
using System;

public class OracleNonQueryExample
{
    public static int UpdateSalary(string connectionString, int employeeId, decimal newSalary)
    {
        string sql = "UPDATE employees SET salary = :new_salary WHERE employee_id = :emp_id";
        int rowsAffected = 0;

        using (OracleConnection connection = new OracleConnection(connectionString))
        {
            using (OracleCommand command = new OracleCommand(sql, connection))
            {
                command.Parameters.Add(new OracleParameter("new_salary", OracleDbType.Decimal) { Value = newSalary });
                command.Parameters.Add(new OracleParameter("emp_id", OracleDbType.Int32) { Value = employeeId });

                try
                {
                    connection.Open();
                    rowsAffected = command.ExecuteNonQuery();
                    Console.WriteLine($"{rowsAffected} row(s) updated.");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error updating salary: " + ex.Message);
                }
            }
        }
        return rowsAffected;
    }
}
                

Using DataAdapter and DataSet/DataTable

For scenarios where you need to retrieve a complete set of data to work with in memory, or to facilitate data manipulation before sending changes back to the database, OracleDataAdapter with DataSet or DataTable is invaluable.

Populating a DataTable


using Oracle.ManagedDataAccess.Client;
using System;
using System.Data;

public class OracleDataAdapterExample
{
    public static DataTable GetEmployeesByDepartment(string connectionString, int departmentId)
    {
        string sql = "SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = :dept_id";
        DataTable dataTable = new DataTable();

        using (OracleConnection connection = new OracleConnection(connectionString))
        {
            using (OracleCommand command = new OracleCommand(sql, connection))
            {
                command.Parameters.Add(new OracleParameter("dept_id", OracleDbType.Int32) { Value = departmentId });

                using (OracleDataAdapter adapter = new OracleDataAdapter(command))
                {
                    try
                    {
                        connection.Open();
                        adapter.Fill(dataTable);
                        Console.WriteLine($"Successfully loaded {dataTable.Rows.Count} employees.");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Error filling DataTable: " + ex.Message);
                    }
                }
            }
        }
        return dataTable;
    }
}
                

Advanced Topics

Stored Procedures

ODP.NET supports calling Oracle stored procedures and functions. You'll use OracleCommand with CommandType.StoredProcedure and manage input/output parameters accordingly.

Transactions

To ensure data integrity, use OracleTransaction to group multiple database operations into a single atomic unit. This allows you to commit or roll back changes as a group.

Asynchronous Operations

For improved application responsiveness, especially in UI applications, ODP.NET supports asynchronous execution of commands (e.g., BeginExecuteReader, EndExecuteReader).

Performance Tuning

Leverage ODP.NET's features like connection pooling, LOB handling, and efficient data retrieval methods to optimize performance. Oracle's documentation provides in-depth guidance on tuning.

Conclusion

ADO.NET, in conjunction with Oracle Data Provider for .NET, offers a robust and efficient solution for .NET developers working with Oracle databases. By understanding the core components and best practices outlined in this document, you can build powerful data-driven applications that interact seamlessly with your Oracle data sources.