Desenvolvimento - C#

C# e Oracle

Neste artigo aborda o acesso a dados usando o Oracle 9i e C#. Embora seja bem simples, o acesso ao Oracle possui particularidades que devem ser levadas em consideração, principalmente por quem está habituado a trabalhar com SQL Server.

por Danielle Monteiro



Neste meu primeiro artigo resolvi falar de um assunto que pode dar trabalho para muitos desenvolvedores, o uso de C#/ VB.net usando uma base Oracle 9i.

O Framework 2005 apesar de maravilhoso, não possui suporte nativo (com a mesma eficiência e eficácia do suporte ao SQL Server 2005) ao Oracle. É necessário destacar que para o desenvolvimento deste tipo de sistemas é preciso baixar um provider específico para este fim o ODP.NET (disponível no site da Oracle http://www.oracle.com/technology/tech/windows/odpnet/index.html, onde podemos ter também informações muito úteis!!!)

Com o provider instalado e o projeto iniciado, além das referências default para acesso aos dados (System.Data e System.Data.Common) é preciso adicionar a seguinte referência ao projeto: Oracle.DataAccess.dll . Sem ela nada funciona!



Porque eu estou falando tudo isso?

O motivo é simples, há algumas diferenças fundamentais entre o Oracle e o SQL Server na manipulação dos dados, principalmente quando os comandos estão armazenados em Packages ou Stored Procedures.

Como a intenção não é promover uma comparação entre o Oracle 9.i e o SQL Server 2005, incluirei aqui somente os códigos usados para a manipulação de dados vindos do Oracle.

Exemplificarei aqui a Consulta de Dados já que no Oracle um select que retorna uma lista de dados tem algumas particularidades. As outras operações não têm muitas mudanças, mas podem ser assunto de uma continuação deste artigo...

Vamos começar pelos scripts...

1 - Usarei para este exemplo uma tabela simples chamada tbCliente:
Create Table tbCliente
 (ID NUMBER NULL,
  Nome VARCHAR2(100) NULL );
2 - Incluir dados na tabela criada:
insert into tbCliente (ID, Nome) values (1, "Astrogildo")
insert into tbCliente (ID, Nome) values (2, "Emengarda")
insert into tbCliente (ID, Nome) values (3, "Rivadavia")
insert into tbCliente (ID, Nome) values (4, "Elidieanildete")
3 - A package que servirá como base para o exemplo é a seguinte:
create or replace package pckCliente is
  	-- Public type declarations
/*Para retornar dados é preciso ter um tipo REF CURSOR declarado na package, 
porque os dados do select serão retornados em um objeto que possua este tipo */
  	TYPE T_CURSOR IS REF CURSOR;
	-- Procedures
/*É preciso ter um parâmetro de saída com o tipo T_Cursor, para que ele receba os dados.*/
	PROCEDURE spr_Cliente(cCursorDados out T_CURSOR);
end pckCliente ;

create or replace package body pckCliente is

/**************************************************************/
/**************************************************************/
/**************************************************************/
PROCEDURE spr_Cliente(cCursorDados out T_CURSOR)
   AS
        /* Criar uma variável do tipo T_Cursor.*/
    V_CURSOR T_CURSOR;
  begin
/* A variável V_Cursor receberá os dados da consulta.*/ 
open V_CURSOR for
      SELECT ID , Nome
        FROM tbCliente;
          /*Atribuir o valor da variável ao parâmetro de saída.*/ 
    cCursorDados := v_cursor;
  exception
	/*Variáveis de Manipulação de Exceções:
sqlcode = Variável que armazena o código de erro;
sqlerrm = variável que armazena a mensagem de erro*/ 
    when others then
      raise_application_error(-20999,
" Erro na consulta de Clientes! (Código do Erro: " || sqlcode ||" // Descrição do Erro: " || sqlerrm || ")");
END spr_Cliente;
/**************************************************************/
/**************************************************************/
/**************************************************************/
end pckCliente ;
Com a tabela criada e preenchida e com a package criada vamos ao código C#. Atenção aos comentários!

1º) Classe que faz acesso aos dados:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
//Declarar a referência para a dll de data types do oracle
using Oracle.DataAccess.Types;
//Declarar a referência para o client do oracle
using Oracle.DataAccess.Client;

namespace Data
{
   public class Data
    {
        /// <summary>
        /// Esta rotina cria o objeto de conexão 
        /// </summary>
        /// <returns>OracleConnection</returns>
        public  OracleConnection GetConnection()
        {
            //String de Conexão
            string connection = "Data 
Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=dani)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=xe))); User Id=system; Password=dani";

            return new OracleConnection(connection);
        }


        /// <summary>
        /// Rotina que executa o comando
        /// <param name="pNomeCmd">Nome do comando que será executado</param>
        /// <param name="pParametros">parâmetros do comando</param>
        /// <returns>string</returns>
        /// </summary>
        /// 
        public DataTable ExecutaComando()
        {
            //Criar um objeto Oracle Connection
            OracleConnection cn = new OracleConnection();
            //Declarar um objeto Oracle Command
            OracleCommand dbCommand = cn.CreateCommand();
            //Criar um objeto DataTable
            DataTable oDt = new DataTable();

            //Atribuir à variável cn o Valor da função GetConnection
            cn = GetConnection();

            //Informar o nome do comando que será executado
            //Como estamos executando uma package devemos colocar
            //O nome da package seguido por um ponto e o nome da procedure
            dbCommand.CommandText = "pckCliente.spr_Cliente";
            //O tipo do comando é StoredProcedure
            dbCommand.CommandType = CommandType.StoredProcedure;
            
            //Criar o tratamento para 
            try
            {
                //A conexão que será usada é a que foi declarada no início do código
                dbCommand.Connection = cn;

                // Adicionar os parametros
                //**Procure preservar o mesmo nome do parâmetro e a mesma ordem em 
				//que ele está declarado na stored procedure**
            
                //Parâmetro de saída cCursorDados 
                //Pontos importantes:
                //O tipo do parâmetro deve ser obrigatóriamente RefCursor
                //Informar sempre a direção do parâmetro: Input, Output , InputOutPut, ReturnValue
                dbCommand.Parameters.Add(new OracleParameter("cCursorDados", 
OracleDbType.RefCursor, ParameterDirection.Output));

                //Criar um objeto Oracle Data Adapter
                OracleDataAdapter oDa = new OracleDataAdapter(dbCommand);

                //Preenchendo o DataTable
                oDa.Fill(oDt);

                //Resultado da Função
                return oDt;

                
            }
            catch (Exception ex)
            {
                if (cn.State == ConnectionState.Open)
                {
                    cn.Close();
                }
                dbCommand.Dispose();
                cn.Dispose();
                throw ex;
               
            }
            finally
            {
                if (cn.State == ConnectionState.Open)
                {
                    cn.Close();
                }
                dbCommand.Dispose();
                cn.Dispose();

            }
        }

    }
}
2º) Console que executa a rotina:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
//Incluir a referência à classe Data
using Data;

namespace Artigo001_090108
{
    class Program
    {
        static void Main()
        {
           
            //Criar um objeto DataTable
            DataTable oDt = new DataTable();

            //Criar um objeto do tipo Data
            Data.Data obj = new Data.Data();

            //Preenchendo o DataTable
            oDt = obj.ExecutaComando();

            Console.WriteLine("Resultado Esperado para a Execução da Package:");
            //Fazendo o Loop nas linhas do DataTable
            foreach (DataRow linhas in oDt.Rows)
            {
                
                Console.WriteLine("ID: " + linhas["ID"].ToString() + " - Nome: " + linhas["Nome"].ToString());
                Console.WriteLine();

            }

            
        }
    }
}
3º) Resultado esperado:



Para finalizar:
  • O grande segredo é que o retorno de um comando select deve estar sempre em um parâmetro de saída;
  • O parâmetro de saída pode ser de diversos tipos, já que com o ODP.NET, teremos suporte a praticamente todos eles.
Quem quiser baixar o código é só clicar aqui!

Enfim, espero que este artigo tenha muita utilidade! Qualquer dúvida, crítica ou sugestão sintam-se a vontade para entrar em contato comigo no email Dani@wbsoft.com.br.

Abraços!
Danielle Monteiro

Danielle Monteiro - Formada pela FATEC-SP, MCP (Microsoft Certified Professional), atua há 7 anos na área de desenvolvimento de sistemas.
Com grande experiência em VB.NET, C#, SQL Server (em diversas versões), Reporting Services 2005 e Oracle (também em diversas versões) é Analista de Sistemas da IT Group.