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!
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:
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!