C# e Oracle

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

    {

        ///

        /// Esta rotina cria o objeto de conexão

        ///

        /// OracleConnection

        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);

        }

 

 

        ///

        /// Rotina que executa o comando

        /// Nome do comando que será executado

        /// parâmetros do comando

        /// string

        ///

        ///

        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:

 img

 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.

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!