Sei sulla pagina 1di 39

Tu t o r i a l d e A D O .

N E T

NPDS
TUTORIAL

Cuiab, 25 de Julho de 2005, 10:11

DE

ADO.NET

Documento: TIPX-1

Pgina 1

Tu t o r i a l d e A D O . N E T

ndice

Lio 1: Introduo ao ADO.NET..........................................................................4


Introduo....................................................................................................... 4
Data Providers.................................................................................................. 4
Objetos ADO.NET.............................................................................................. 5
O objeto OracleConnection.............................................................................. 5
O objeto OracleCommand............................................................................... 5
O objeto OracleDataReader............................................................................. 5
O objeto DataSet........................................................................................... 5
O objeto OracleDataAdapter............................................................................ 5
Sumrio.......................................................................................................... 6
Lio 2: O Objeto OracleConnection.....................................................................7
Introduo....................................................................................................... 7
Criando um objeto OracleConnection................................................................... 7
Usando o OracleConnection................................................................................ 8
Sumrio.......................................................................................................... 9
Lio 3: O Objeto OracleCommand.................................................................... 11
Introduo..................................................................................................... 11
Criando um objeto OracleCommand................................................................... 11
Consultando dados.......................................................................................... 11
Inserindo dados.............................................................................................. 12
Atualizando dados........................................................................................... 12
Apagando dados............................................................................................. 13
Obtendo valores simples.................................................................................. 13
Colocando tudo junto....................................................................................... 13
Sumrio......................................................................................................... 18
Lio 4: Lendo dados com OracleDataReader.....................................................19
Introduo..................................................................................................... 19
Criando um objeto OracleDataReader................................................................. 19
Terminando.................................................................................................... 20
Sumrio......................................................................................................... 22
Lio 5: Trabalhando com dados desconectados................................................23
Introduo..................................................................................................... 23
Criando um objeto DataSet............................................................................... 23
Criando um OracleDataAdapter......................................................................... 24
Preenchendo o DataSet.................................................................................... 24
Usando o DataSet........................................................................................... 25
Atualizando as mudanas................................................................................. 25
Colocando tudo junto....................................................................................... 25
Sumrio......................................................................................................... 27
Lio 6: Adicionando parmetros em comandos................................................ 28
Introduo..................................................................................................... 28
Preparando um objeto OracleCommand com parmetros....................................... 28
Declarando objetos OracleParameter.................................................................. 29
Associando um objeto OracleParameter a um OracleCommand.............................. 29
Colocando tudo junto....................................................................................... 29
Sumrio......................................................................................................... 31
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 2

Tu t o r i a l d e A D O . N E T

Lio 7: Usando Stored Procedures................................................................... 32


Introduo..................................................................................................... 32
Executando uma stored procedure..................................................................... 32
Enviando parmetros para uma stored procedure................................................. 32
Colocando tudo junto....................................................................................... 33
Sumrio......................................................................................................... 35
Lio 8: Trabalhando com transaes................................................................37
Introduo..................................................................................................... 37
Criando transaes com ADO.NET...................................................................... 37
Sumrio......................................................................................................... 39

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 3

Tu t o r i a l d e A D O . N E T

Lio 1: Introduo ao ADO.NET

Essa lio faz uma introduo a ADO.NET. Ela inclui conceitos bsicos de ADO.NET e os
objetos que voc conhecer em lies posteriores. Aqui vai os objetivos desta lio:
1.
2.
3.
4.
5.
6.
7.

Aprender o que ADO.NET


Entender o que um data provider
Entender o que um objeto de conexo
Entender o que um objeto de comando
Entender o que o objeto DataReader
Entender o que o objeto DataSet
Entender o que o objeto DataAdapter

Introduo
ADO.NET um conjunto de bibliotecas orientadas a objeto que permite seu cdigo
interagir com fontes de bancos. Normalmente, uma fonte de dados um banco de dados,
mas tambm pode ser um arquivo de texto, uma planilha do Excel, ou um arquivo XML.
Para os propsitos deste tutorial, vamos ver como o ADO.NET interage com bancos de
dados.
Como voc provavelmente deve saber, existem muitos tipos diferentes de bancos de
dados por a. Por exemplo, existe o SQL Server, o Oracle, o Interbase e o DB2, s para
dar nome a alguns. Para refinar o escopo deste tutorial, os exemplos sero focados no
Oracle Database Server.
Data Providers
Ns j sabemos que ADO.NET permite interagir com diferentes tipos de fontes de dados e
diferentes tipos de bancos de dados. Por causa disso, h um conjunto de classes
diferenciadas para tratar os diferentes protocolos envolvidos. Algumas fontes de dados
usam ODBC, portanto utilizam o protocolo OleDb, j outras fontes de dados podem
requerer um protocolo prprio para acesso.
ADO.NET oferece uma interface comum para acesso a vrias fontes de dados, mas vem
em diferentes conjuntos de classes para que voc converse com cada fonte de dado
diferente. Essas bibliotecas so chamadas Data Providers e normalmente so nomeadas
com o protocolo ou tipo de fonte de dados utilizado por ele. A tabela 1.1 lista alguns data
providers conhecidos, o prefixo de API que eles usam e o tipo de fonte de dados com que
eles interagem.
Nome do
provider

Prefixo de
API

Descrio da fonte de dados

ODBC

Odbc

Fontes de dados com interface ODBC. Normalmente so


fontes de dados mais antigas

OLE DB

OleDb

Fontes de dados que possuem interfaces OLE DB, como


Access e Excel

Oracle

Oracle

Para bases de dados Oracle

SQL

Sql

Para interagir com bases SQL Server

Borland

Bdp

Acesso genrico para vrios bancos de dados, como


Interbase, SQL Server, IBM DB2 e Oracle

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 4

Tu t o r i a l d e A D O . N E T

Tabela 1.1: Data providers conhecidos para .NET


O prefixo de API funciona de acordo com o seguinte exemplo: um dos primeiros objetos
ADO.NET que voc aprender o objeto de conexo, que permite que voc estabelea
uma conexo com o banco de dados. Se voc estiver utilizando o data provider de OLE
DB para conectar a um banco que possui interface OLE DB (como Access), voc precisa
utilizar a classe de conexo chamada OleDbConnection. Se voc for utilizar um banco de
dados Oracle, voc precisa se conectar utilizando a classe de conexo OracleConnection.
Objetos ADO.NET
ADO.NET inclui muitos objetos que voc utiliza para acessar dados. Esta seo introduz
alguns dos principais objetos que voc utilizar. Mais tarde neste tutorial, voc aprender
mais sobre cada objeto. Os objetos abaixo so os que voc precisa conhecer. Aprendendo
sobre eles dar a voc uma idia dos tipos de coisas que voc pode fazer com ADO.NET.
O objeto OracleConnection
Para interagir com um banco de dados, voc precisa se conectar a ele. A conexo ajuda a
identificar o servidor do banco de dados, o nome do usurio, a senha, e outros
parmetros requeridos para se conectar a um banco de dados. Uma conexo de banco de
dados utilizada para por objetos de comando para que eles possam saber em qual
banco de dados ele ir executar o comando.
O objeto OracleCommand
Interagir com um banco de dados quer dizer que voc precisa especificar as aes que
voc quer que aconteam. Isso feito com um objeto de comando. Voc usa um objeto
de comando para enviar comandos SQL para um banco de dados. Um objeto de comando
utiliza um objeto de conexo para saber em qual banco de dados executar as aes. Voc
pode utilizar o objeto de comando sozinho, para executar o comando diretamente, ou
atribuir um objeto de comando a um OracleDataAdapter, que possui um conjunto de
objetos de comando que funcionam como grupo, como especificado a seguir.
O objeto OracleDataReader
Muitas operaes em dados requerem que voc obtenha um conjunto de valores do
banco de dados para leitura. O objeto OracleDataReader permite que voc obtenha os
resultados de um comando SELECT (executado por um objeto de comando). Por razes
de performance, os dados retornados por um OracleDataReader (e qualquer DataReader
do ADO.NET) somente leitura e de leitura com apenas uma direo. Isso significa que
voc pode ler dados de um DataReader apenas de maneira seqencial. Isso bom para a
performance, mas se voc precisa manipular dados, ento voc precisa de um objeto
DataSet.
O objeto DataSet
Objetos DataSet so a representao em memria de dados. Um DataSet pode conter
mltiplos DataTable, que contm colunas e linhas, como uma tabela normal de banco de
dados. Voc pode at mesmo definir relaes entre as tabelas para criar relaes paifilho. O DataSet especialmente interessante para ajudar a manipular dados em
memria e realizar operaes de dados de forma desconectada, quando o cenrio se
aplica. O DataSet um objeto utilizado por todos os Data Providers, e portanto no h
prefixo em seu nome.
O objeto OracleDataAdapter
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 5

Tu t o r i a l d e A D O . N E T

Voc normalmente utiliza um objeto DataSet para fazer cache de dados que so
utilizados mais para leitura, e faz poucas atualizaes na fonte de dados real. O objeto
OracleDataAdapter utilizado para fazer a ligao entre um DataSet e a fonte de dados.
Uma vez que o DataSet um conjunto de dados desconectado e independente de fonte
de dados, quando voc o utiliza para trabalhar com dados, s vezes voc precisa
transmitir suas atualizaes do DataSet para a fonte de dados. O OracleDataAdapter
contm comandos SELECT, INSERT, UPDATE e DELETE para realizar essa transferncia.
Assim, voc pode utilizar o objeto OracleDataAdapter para preencher um DataSet com
dados do banco, e para atualizar o banco de dados com o contedo do DataSet.
Sumrio
ADO.NET a tecnologia de .NET utilizada para interagir com fontes de dados. Voc tem
vrios Data Providers, que so utilizadas para se comunicar com vrias fontes de dados,
dependendo do banco de dados que voc vai utilizar. Apesar disso, voc tem uma
estrutura de classes similar para todos os Data Providers. O objeto OracleConnection
deixa voc se conectar a uma fonte de dados, o objeto OracleCommand permite que voc
envie comandos fonte de dados. Para ter acesso somente leitura rpida ao dados, voc
pode utilizar um objeto OracleDataReader. Se voc quiser trabalhar com dados
desconectados, use um DataSet e implemente a leitura e escrita ao banco de dados com
um objeto OracleDataAdapter.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 6

Tu t o r i a l d e A D O . N E T

Lio 2: O Objeto OracleConnection

Essa lio descreve o objeto OracleConnection e como se conectar ao banco de dados. Os


objetivos da lio so:

Saber para que os objetos de conexo so usados


Aprender a inicializar um objeto OracleConnection
Entender como o objeto OracleConnection usado em aplicaes
Compreender a importncia de um gerenciamento eficiente de conexes

Introduo
A primeira coisa que voc precisa aprender quando estiver interagindo com banco de
dados que voc precisa criar uma conexo com o banco de dados. A conexo diz ao
resto cdigo ASP.NET em que banco de dados voc est falando. Ela gerencia toda a
lgica de baixo nvel associada aos protocolos de comunicao com o banco de dados. O
objeto de conexo deixa as coisas fceis para voc porque tudo o que voc precisa fazer
instanciar um objeto de conexo, abrir a conexo e, depois de todo o trabalho, fechar a
conexo.
Embora seja muito fcil trabalhar com conexes em ADO.NET, voc precisa entender que
as conexes para fazer decises acertadas quando codificar rotinas de manipulao de
dados. Claro, se voc tem uma aplicao cliente que trabalha com uma base de dados
em uma nica mquina, voc provavelmente no se importar com o objeto de conexo.
No entanto, pense em uma aplicao grande onde centenas de usurios na companhia
esto acessando o mesmo banco de dados. Cada conexo representa uma sobrecarga e
s pode haver uma quantidade finita de sobrecarga que o servidor pode suportar. Para
visualizar um caso mais extremo, pense em um Web site que acessado por milhares de
usurios por dia. Aplicaes que criam conexes e no as liberam podem causar impactos
negativos em performance e escalabilidade.
Criando um objeto OracleConnection
Um OracleConnection um objeto, como qualquer objeto C#. Na maioria das vezes, voc
declara e instancia um objeto OracleConnection ao mesmo tempo, com uma sintaxe
como a seguinte:
OracleConnection
conn
Id=hr;Password=hr);

new

OracleConnection(Server=apisora2;User

O objeto OracleConnection instanciado acima usa o construtor com um nico argumento


string. Este argumento chamado de string de conexo. A tabela 2.1 mostra as partes
mais comuns de uma string de conexo.
Nome do parmetro
da string de conexo

Descrio

Server

Identifica o servidor. Utiliza-se o nome de servio configurado


no cliente Oracle instalado na mquina de onde est sendo
executado o programa

User Id

Nome do usurio Oracle no banco de dados

Password

Senha do usurio Oracle no banco de dados

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 7

Tu t o r i a l d e A D O . N E T

Tabela 2.1: Parmetros da string de conexo


Usando o OracleConnection
O propsito de criando um objeto OracleConnection fazer o restante do seu cdigo
ADO.NET funcionar com um banco de dados. Outros objetos ADO.NET, como
OracleCommand e OracleDataAdapter utiliza um OracleConnection com parmetro. A
seqncia de operaes na vida de um OracleConnection a seguinte:
1.
2.
3.
4.
5.

Instanciar um objeto OracleConnection


Abrir a conexo
Passar a conexo para outros objetos ADO.NET
Realizar operaes com o banco de dados com outros objetos ADO.NET
Fechar a conexo

Ns j vimos como inicializar um OracleConnection. O resto dos passos (abrir, fechar,


usar, passar) mostrado no cdigo a seguir.
Listagem 2.1 Usando um OracleConnection
using System;
using System.Data.OracleClient;
namespace Tecnomapas.Tutoriais.AdoNet
{
class DemoOracleConnection
{
[STAThread]
static void Main(string[] args)
{
// 1. Instancializa a conexo
OracleConnection conn = new OracleConnection(
"Server=apisora2;User Id=hr;Password=hr");
OracleDataReader rdr = null;
try
{

// 2. Abre a conexo
conn.Open();

// 3. Passa a conexo para um objeto de comando


OracleCommand cmd = new OracleCommand("select
from hr.employees", conn);

// 4. Usa a conexo
// Obtm os dados da consulta
rdr = cmd.ExecuteReader();
// Imprime o id de cada empregado
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}

}
finally
{
// Fecha o reader
if (rdr != null)
{
rdr.Close();

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 8

Tu t o r i a l d e A D O . N E T

}
// 5. Fecha a conexo
if (conn != null)
{
conn.Close();
}
}

Console.Read();

Como mostrado na listagem 2.1, voc abre uma conexo chamando o mtodo Open() da
instncia de OracleConnection, conn. Qualquer operao em uma conexo que ainda no
foi aberta pode gerar uma exceo. Portanto, voc precisa abr-la antes de us-la.
Antes de usar a conexo, voc precisa deixar seu cdigo ADO.NET saber que conexo ele
vai usar. Na listagem 2.1, ns configuramos o segundo parmetro do construtor do
OracleCommand como o nosso objeto j instanciado OracleConnection, conn. Qualquer
operao com OracleCommand utilizar a conexo criada com o objeto conn.
O cdigo que usa a conexo o objeto OracleCommand, que faz uma consulta na tabela
employees do esquema hr, no banco de dados apisora2. O conjunto de dados
retornado em um objeto OracleDataReader e o loop while faz leituras de cada coluna
deste conjunto de dados retornado. Neste caso, a impresso a listagem dos ids de cada
empregado. Mais tarde discutiremos os objetos OracleCommand e OracleDataReader, por
enquanto importante que voc entenda que esses objetos da listagem esto usando a
conexo instanciada no incio do programa.
Quando voc estiver terminado de utilizar o objeto de conexo, voc precisa fech-lo. Se
voc no fizer isso, poder estar comprometendo seriamente a performance do servidor
de sua aplicao. H apenas alguns pontos alm de simplesmente fechar a conexo com
seu mtodo Close(): ns fazemos isso dentro de um bloco finally e nos certificamos
que a conexo no null antes de chamarmos o mtodo.
Note que o cdigo ADO.NET est dentro de um bloco try/finally. Como descrito na
Lio 15: Tratamento de excees do tutorial de C#, os blocos de finally so garantidos
de serem executados mesmo que uma exceo ocorra dentro do bloco try. Uma vez que
conexes com bancos de dados so um recurso dispendioso, ns queremos ter certeza
que a conexo ser fechada custe o que custar.
Outra precauo verificar se a varivel que deveria indicar uma referncia para um
objeto de conexo no null. Se alguma coisa sai errada quando voc instancia o objeto
OracleConnection, a varivel ser configurada como null e voc vai querer ter certeza
que no est tentando fechar uma conexo invlida (o que geraria uma conexo).
Esse exemplo mostra como usar um objeto OracleConnection com um objeto
OracleDataReader. Isso requer que voc explicitamente abra e feche a conexo. Quando
voc estiver trabalhando com o modelo desconectado, voc no vai precisar abrir e
fechar conexes por conta prpria. Voc ver isso nas lies sobre o OracleDataAdapter.
Sumrio
Os objetos OracleConnection permitem que o cdigo ADO.NET saiba em que banco de
dados conectar e agir. Eles so instanciados passando uma string de conexo que contm
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 9

Tu t o r i a l d e A D O . N E T

os dados necessrios da conexo, como servidor, senha e nome de usurio. Os passos


utilizados para gerenciar uma conexo so: instanciar, abrir, passar, usar e fechar. Tenha
certeza de fechar as conexes nos momentos certos para evitar problemas na sua
aplicao e no servidor de banco de dados.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 10

Tu t o r i a l d e A D O . N E T

Lio 3: O Objeto OracleCommand

Esta lio descreve o objeto OracleCommand e como voc deve utiliz-lo para interagir
com um banco de dados. A vai os objetivos da lio:

Saber o que um objeto de comando


Aprender a utilizar o mtodo ExecuteDataReader() para ler dados de consultas
Aprender a utilizar o mtodo ExecuteNonQuery() para inserir e remover dados
Aprender a utilizar o mtodo ExecuteScalar() para retornar um valor simples

Introduo
Um objeto OracleCommand permite a voc especificar que tipo de interao voc quer
realizar com o banco de dados. Por exemplo, voc pode fazer seleo, inserir, atualizar e
remover registros. O objeto OracleCommand pode ser usado para trabalhar com dados
desconectados, mas esta lio ensinar apenas a implementar uma aplicao que usa um
nico objeto OracleCommand. A lio sobre OracleDataAdapter mostrar como utilizar
dados desconectados. Essa lio ensina ainda como recuperar um valor simples de um
banco de dados, como o nmero de registros de uma tabela.
Criando um objeto OracleCommand
Similarmente a outros objetos de C#, voc instancia um objeto OracleCommand j na
declarao da varivel, como o seguinte:
OracleCommand cmd = new OracleCommand(select first_name from employees,
conn);
A linha acima bastante tpica para inicializar um objeto OracleCommand. Ela tem um
parmetro de string que armazena o comando que voc quer executar e uma referncia
para um objeto de conexo. O construtor de OracleCommand tem algumas sobrecargas,
as quais voc poder ver em exemplos neste tutorial.
Consultando dados
Quando voc usa um comando SELECT de SQL, voc obtm um conjunto de dados para
visualizao. Para realizar isso com um objeto OracleCommand, voc pode usar o mtodo
ExecuteReader() que retorna um objeto OracleDataReader. Ns vamos discutir o objeto
OracleDataReader no futuro. O exemplo abaixo mostra como voc usa o OracleCommand
para obter um objeto OracleDataReader.
// 1. Instancia um novo objeto comando com a consulta e a conexo.
OracleCommand cmd = new OracleCommand(select first_name from employees,
conn);
// 2. Chama ExecuteReader() para obter o resultado da consulta
OracleDataReader dr = cmd.ExecuteReader();
No exemplo acima, ns inicializamos um objeto OracleCommand, passando a string de
comando e o objeto de conexo como parmetros para o construtor. Ento ns obtemos
um objeto OracleDataReader ao chamar o mtodo ExecuteReader() do objeto de
comando, cmd.
Este cdigo parte da listagem 3.1 na seo Colocando tudo junto desta lio.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 11

Tu t o r i a l d e A D O . N E T

Inserindo dados
Para inserir dados em um banco de dados, use o mtodo ExecuteNonQuery() do objeto
OracleCommand. O cdigo seguinte mostra como inserir dados em uma tabela de banco
de dados:
// Prepara a string de comando
string insertString = @
insert into hr.jobs
(job_id, job_title, min_salary, max_salary)
values ('IT_TEST', 'Tester', 4000, 10000);
// 1. Instancia um novo comando com uma consulta e uma conexo
OracleCommand cmd = new OracleCommand(insertString, conn);
// 2. Chama ExecuteNonQuery() para enviar o comando
cmd.ExecuteNonQuery();
A instancializao do OracleCommand um pouco diferente da qual voc j viu, mas
basicamente a mesma. Ao invs de passar um literal de string para o construtor do
objeto, ns passamos uma varivel inicializada. A varivel insertString declarada
logo acima do objeto OracleCommand.
Uma observao que pode ser feita que no comando de insero ns especificamos
explicitamente as colunas da tabela. Isso interessante porque a tabela pode ser
modificada para comportar mais colunas, e nosso cdigo no precisa ser alterado.
Para executar este comando, ns simplesmente chamamos o mtodo ExecuteNonQuery
() da instncia do OracleCommand, cmd.
Atualizando dados
O mtodo ExecuteNonQuery() pode ser utilizado para atualizar dados. O cdigo seguinte
mostra como atualizar dados.
// Prepara a string de comando
string updateString = @
update employees
set min_salary * 1.1
where job_id = 'IT_TEST';
// 1. Instancia um novo comando com a string de comando apenas
OracleCommand cmd = new OracleCommand(updateString);
// 2. Configura a propriedade de conexo
cmd.Connection = conn;
// 3. Chama ExecuteNonQuery()
cmd.ExecuteNonQuery();

para enviar o comando

Novamente, ns colocamos o comando SQL em uma varivel, mas desta vez ns


passamos apenas a string de comando para o construtor do comando. No passo 2, ns
atribumos o objeto de conexo propriedade Connection do objeto de comando.
Isso poderia ter sido feito mesmo se o construtor tivesse utilizado dois parmetros. Isso
demonstra que voc pode mudar o objeto de conexo do comando a qualquer momento.
O mtodo ExecuteNonQuery() executa o comando de atualizao.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 12

Tu t o r i a l d e A D O . N E T

Apagando dados
Voc pode apagar dados usando o mtodo ExecuteNonQuery(). O exemplo seguinte
mostra como apagar dados de uma base de dados com o mtodo ExecuteNonQuery():
// Prepara a string de comando:
string deleteString =@
delete from employees
where job_id = 'IT_TEST';
// 1. Instancia um novo comando
OracleCommand cmd = new OracleCommand();
// 2. Configura a propriedade CommandText
cmd.CommandText = deleteString;
// 3. Configura a propriedade Connection
cmd.Connection = conn;
// 4. Chama ExecuteNonQuery() para enviar o comando
cmd.ExecuteNonQuery();
Esse exemplo mostra como usar o construtor de OracleCommand sem parmetros.
Depois, ele configura as propriedades CommandText com a string de comando, e
Connection com o objeto de conexo.
Ns poderamos ter utilizado os outros dois construtores de OracleCommand para criar
um objeto de comando de DELETE, mas utilizamos o construtor padro para demonstrar
que a string de comando e a conexo podem ser modificadas a qualquer momento depois
de o objeto ser instanciado.
Obtendo valores simples
s vezes voc precisa consultar o banco de dados para obter um nico valor, como a
contagem de linhas de uma tabela ou a hora atual do banco de dados. possvel fazer
isso utilizando o mtodo ExecuteDataReader(), mas esse no o mtodo mais eficiente.
A melhor forma de se fazer isso seria enviar o comando ao banco de dados e esperar
como retorno o valor requerido. Isso pode ser feito com ADO.NET da seguinte forma:
// 1. Intancia o novo comando
OracleCommand cmd = new OracleCommand(select
conn);

count(*) from

employees,

// 2. Chama o mtodo ExecuteScalar() para retornar um valor simples


int valor = (int) cmd.ExecuteScalar();
A consulta no construtor do objeto OracleCommand retorna a quantidade de registros na
tabela employees. Este um valor simples, um nmero inteiro. O mtodo
ExecuteScalar() no passo 2 retorna este valor. Uma vez que o tipo de retorno de
ExecuteScalar() object, ns fazemos uma converso explcita para int.
Colocando tudo junto
Por simplicidade, ns mostramos pequenos trechos de cdigo para apresentar a sintaxe
de manipulao de dados com o OracleCommand. Mas tambm til ter uma listagem
inteira de cdigo para ver como tudo isso pode ser usado em um programa. A listagem
3.1 mostra o cdigo usado nesta lio em um programa executvel.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 13

Tu t o r i a l d e A D O . N E T

Listagem 3.1: Demonstrando o OracleConnection


using System;
using System.Data;
using System.Data.OracleClient;
namespace Tecnomapas.Tutoriais.AdoNet
{
/// <summary>
/// Demonstra como trabalhar com objetos OracleCommand
/// </summary>
class DemoOracleCommand
{
OracleConnection conn;
public DemoOracleCommand()
{
// Inicializa uma conexo
conn = new OracleConnection(
"Data
Id=fsomalia;Password=654321");
}

Source=apisora2;User

// Chama mtodos que demonstram as capacidades do OracleCommand


static void Main()
{
DemoOracleCommand doc = new DemoOracleCommand();
Console.WriteLine();
Console.WriteLine("Empregados Antes de Inserir");
Console.WriteLine("-----------------------------");
// Usa o mtodo ExecuteReader
doc.ReadData();
// Usa o mtodo ExecuteNonQuery para inserir
doc.InsertData();
Console.WriteLine();
Console.WriteLine("Empregados Aps Inserir");
Console.WriteLine("-----------------------------");
doc.ReadData();
// Usa o mtodo ExecuteNonQuery para atualizar
doc.UpdateData();
Console.WriteLine();
Console.WriteLine("Empregados Aps Atualizar");
Console.WriteLine("-----------------------------");
doc.ReadData();
// Usa o mtodo ExecuteNonQuery para apagar
doc.DeleteData();
Console.WriteLine();
Console.WriteLine("Empregados Aps Apagar");
Console.WriteLine("------------------------------");
doc.ReadData();
// Usa o mtodo ExecuteScalar
int numberOfRecords = doc.GetNumberOfRecords();

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 14

Tu t o r i a l d e A D O . N E T

numberOfRecords);
}

Console.WriteLine();
Console.WriteLine("Nmero

de

registros:

{0}",

Console.Read();

/// <summary>
/// Usa o mtodo ExecuteReader
/// </summary>
public void ReadData()
{
OracleDataReader dr = null;
try
{

consulta e a conexo.

// Abre a conexo
conn.Open();
//

1.

Instancia

OracleCommand
first_name from hr.employees", conn);

cmd

um

novo
=

new

objeto

comando

com

OracleCommand("select

// 2. Chama ExecuteReader() para obter o resultado

da consulta

dr = cmd.ExecuteReader();
// Imprime o primeiro nome de todos os empregados
while (dr.Read())
{
Console.WriteLine(dr[0]);
}

}
finally
{
// Fecha o reader
if (dr != null)
{
dr.Close();
}

// Fecha a conexo
if (conn != null)
{
conn.Close();
}

/// <summary>
/// Usa o mtodo ExecuteNonQuery para inserir
/// </summary>
public void InsertData()
{
try
{
// Abre a conexo
conn.Open();
// Prepara a string de comando
string insertString = @"
insert into hr.jobs
(job_id, job_title, min_salary, max_salary)
values ('IT_TEST', 'Tester', 4000, 10000)";

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 15

Tu t o r i a l d e A D O . N E T

// 1. Instancia um novo comando com uma consulta e

uma conexo

OracleCommand cmd = new OracleCommand(insertString,

conn);

// 2. Chama ExecuteNonQuery() para enviar o comando


cmd.ExecuteNonQuery();

}
finally
{
// Fecha a conexo
if (conn != null)
{
conn.Close();
}
}

/// <summary>
/// Usa o mtodo ExecuteNonQuery para atualizar
/// </summary>
public void UpdateData()
{
try
{
// Abre a conexo
conn.Open();
// Prepara a string de comando
string updateString = @"
update hr.employees
set min_salary * 1.1
where job_id = 'IT_TEST'";
comando apenas
(updateString);

// 1. Instancia um novo comando com a string de


OracleCommand

cmd

new

OracleCommand

// 2. Configura a propriedade de conexo


cmd.Connection = conn;
//

comando

3.

Chama

ExecuteNonQuery()

para

enviar

cmd.ExecuteNonQuery();
}
finally
{
// Fecha uma conexo
if (conn != null)
{
conn.Close();
}
}

/// <summary>
/// Usa o mtodo ExecuteNonQuery para apagar
/// </summary>
public void DeleteData()
{
try
{
// Abre a conexo
conn.Open();
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 16

Tu t o r i a l d e A D O . N E T

// Prepara a string de comando:


string deleteString =@"
delete from hr.employees
where job_id = 'IT_TEST'";
// 1. Instancia um novo comando
OracleCommand cmd = new OracleCommand();
// 2. Configura a propriedade CommandText
cmd.CommandText = deleteString;
// 3. Configura a propriedade Connection
cmd.Connection = conn;
// 4. Chama ExecuteNonQuery() para enviar o comando
cmd.ExecuteNonQuery();

}
finally
{
// Fecha a conexo
if (conn != null)
{
conn.Close();
}
}

/// <summary>
/// Usa o mtodo ExecuteScalar
/// </summary>
/// <returns>number of records</returns>
public int GetNumberOfRecords()
{
int valor = -1;
try
{

// Abre a conexo
conn.Open();

// 1. Intancia o novo comando


OracleCommand cmd = new OracleCommand("select count
(*) from hr.employees", conn);
um valor simples

// 2. Chama o mtodo ExecuteScalar() para retornar


valor = (int) cmd.ExecuteScalar();
}
finally
{
// Fecha a conexo
if (conn != null)
{
conn.Close();
}
}
return valor;

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 17

Tu t o r i a l d e A D O . N E T

Na listagem 3.1, um objeto OracleConnection instanciado no construtor do programa.


Este objeto ser limpado da memria quando o coletor de lixo for ativado, aps o trmino
do programa. O importante lembrar de fechar a conexo sempre que se terminar de
utiliz-la. Este programa abre as conexes em um bloco try e as fecha em um bloco de
finally.
O mtodo ReadData() mostra o contedo da coluna first_name da tabela employees do
esquema hr. Ns o utilizamos vrias vezes durante o programa para mostrar as
modificaes realizadas com os mtodos de inserir, remover e alterar registros.
E antes de acabar a lio, mais um truque: embora tenhamos ignorado, o mtodo
ExecuteNonQuery() retorna um valor. Seu tipo int e indica quantos registros foram
alterados pelo mtodo. Por exemplo, na chamada de ExecuteNonQuery() que insere
dados, o valor retornado seria 1. Isto interessante para fazer checagem de quantidade
de registros alterados durante uma remoo e atualizao de dados.
Sumrio
Um objeto OracleCommand permite enviar dados para o banco de dados. Ele tem
mtodos especializados para diferentes tipos de comandos. Para retornar um valor
simples, utilizamos ExecuteScalar(). Para retornar um conjunto de dados, utilizamos
ExecuteReader(). E para alterar, inserir e remover dados, utilizamos ExecuteNonQuery
().

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 18

Tu t o r i a l d e A D O . N E T

Lio 4: Lendo dados com OracleDataReader

Esta lio explica como ler dados com um objeto OracleDataReader. A vai os objetivos
da lio:

Aprender o que o OracleDataReader


Saber como ler dados com o OracleDataReader
Entender a necessidade de se fechar um OracleDataReader

Introduo
O OracleDataReader uma classe boa para se ler dados da melhor maneira possvel.
Voc no pode utiliz-lo para escrever dados. Voc no pode utiliz-lo para navegar
aleatoriamente entre os dados. O OracleDataReader descrito como um stream
unidirecional somente-leitura.
Isso quer dizer que com o OracleDataReader s possvel ler dados, e de maneira
seqencial. Quando voc obtm os dados de um OracleDataReader, voc precisa salvlos (em variveis, por exemplo), porque voc no mais poder obt-los novamente do
mesmo OracleDataReader.
A vantagem do OracleDataReader ser seqencial que ele pode ser rpido. Ele no tem a
sobrecarga adicional de transversar entre os dados e escrever no banco de dados.
Portanto, se voc quer apenas ler alguns dados uma vez, e o quer fazer da forma mais
rpida possvel, o OracleDataReader sua melhor escolha. Alm disso, se a quantidade
de dados que voc deseja ler em uma nica chamada maior da que voc prefereria
manter em memria, utilizar um stream como o OracleDataReader tambm uma boa
idia.
Nota: Observe que eu utilizei o termo uma vez ao enumerar as vantagens de se utilizar
um OracleDataReader. Como quase tudo, isso tem suas excees. s vezes, melhor,
para a performance da aplicao, que voc faa cache de dados, para evitar o overhead
de conexo e rede associadas a comunicao com banco de dados. Nestes casos, voc
poder utilizar um OracleDataAdapter para preencher um DataTable. Esses itens sero
vistos na prxima lio.
Criando um objeto OracleDataReader
As sees anteriores j continham um OracleDataReader. Esta lio mostra como utilizar
um OracleDataReader, com base naquilo que voc j viu.
Como explicado anteriormente, o OracleDataReader retorna dados via um stream
somente-leitura seqencial. Para ler estes dados, voc precisa puxar dados do Reader
linha por linha. Uma vez que uma linha foi lida, a linha anterior no mais estar
disponvel. Para ler a linha anterior novamente, voc precisa criar uma nova instncia de
OracleDataReader e ler at aquele ponto novamente.
O mtodo mais tpico de se ler um OracleDataReader iterar por cada linha dele em um
loop while. O cdigo seguinte mostra exatamente isso:
while (rdr.Read())
{
// Obtm resultados de cada coluna
string nome = (string) rdr[first_name];
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 19

Tu t o r i a l d e A D O . N E T

string sobrenome = (string) rdr[last_name];


string email = (string) rdr[email];

// Imprime os resultados
Console.Write({0,-25}, nome);
Console.Write({0,-20}, sobrenome);
Console.Write({0,-25}, email);
Console.WriteLine();

Note a chamada de Read() da instncia de OracleDataReader, rdr, como condio do loop


while. O valor de retorno de Read() do tipo bool, e indica se h registros para ler.
Depois que o ltimo registro foi lido, Read() retorna false.
Nas lies anteriores, ns extramos a primeira coluna da linha utilizando um indexador
de OracleDataReader. H dois indexadores neste objeto, um indexado pela posio da
coluna na consulta (um int) e um indexado pelo nome da coluna (uma string). Voc
perceber que utilizar o indexador com string bem mais legvel do que o indexador
com int. O exemplo acima sua indexadores com string.
Qualquer que seja o indexador, valor retornado por ele sempre object. Isso
necessrio porque de uma consulta de banco de dados por vir qualquer coisa (strings,
nmeros, datas, valores binrios, etc). por isso que fazemos a converso explcita para
string na atribuio.
Terminando
Sempre lembre-se de fechar o OracleDataReader, da mesma forma que voc precisa
fechar o OracleConnection. Coloque esses cdigos dentro de um bloco finally, para ter
certeza de que ele ser executado.
try
{

// Cdigo de acesso a dados


}
finally
{
// 3. Fecha o reader
if (rdr != null)
{
rdr.Close();
}
// Feche a conexo tambm
}
O cdigo acima verificar se OracleDataReader foi instanciado. Depois que o cdigo sabe
que uma boa instncia de OracleDataReader foi criada, ela fechada com o mtodo
Close(). A listagem 4.1 mostra o cdigo inteiro desta seo.
Listagem 4.1: Usando o OracleDataReader
using System;
using System.Data;
using System.Data.OracleClient;
class ReaderDemo
{
static void Main()
{
ReaderDemo rd = new ReaderDemo();

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 20

Tu t o r i a l d e A D O . N E T

rd.SimpleRead();

public void SimpleRead()


{
// Declara um OracleDataReader, que ser usado
// nos blocos de try e finally
OracleDataReader rdr = null;
// Cria um objeto de conexo
OracleConnection conn = new OracleConnection(
"Data Source=apisora2;User Id=fsomalia;Password=654321");
// Cria um objeto de comando
OracleCommand cmd = new OracleCommand(
"select
e.first_name,
e.last_name,
hr.employees e", conn);
try
{

e.email

from

// Abre a conexo
conn.Open();
// 1. Obtem uma instancia de OracleDataReader
rdr = cmd.ExecuteReader();
// Imprime cabealhos de colunas
Console.WriteLine(
"Nome

Email");
------------");

Console.WriteLine(
"------------

Sobrenome
------------

// 2. Imprime as colunas necessrias


while (rdr.Read())
{
// Obtem os valores de cada coluna
string nome = (string)rdr["first_name"];
string sobrenome = (string)rdr["last_name"];
string email
= (string)rdr["email"];
// Imprime os valores
Console.Write("{0,-20}", nome);
Console.Write("{0,-25}", sobrenome);
Console.Write("{0,-25}", email);
Console.WriteLine();

}
Console.Read();

}
finally
{
// 3. Fecha o reader
if (rdr != null)
{
rdr.Close();
}

// Fecha a conexo
if (conn != null)
{
conn.Close();
}

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 21

Tu t o r i a l d e A D O . N E T

}
Sumrio
Objetos OracleDataReader permitem que voc leia dados de um banco de dados de forma
rpida e seqencial. Voc obtm os dados lendo cada coluna do stream de dados. Chame
o mtodo Close() para fechar o reader e ter certeza de que no haver falta de recursos.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 22

Tu t o r i a l d e A D O . N E T

Lio 5: Trabalhando com dados desconectados

Esta lio explica como trabalhar com dados desconectados,


OracleDataAdapter e DataSet. A vai os objetivos da lio:

usando

objetos

Entendendo a necessidade de dados desconectados


Entendendo para que serve o objeto DataSet
Aprendendo a usar o OracleDataAdapter para recuperar e atualizar dados

Introduo
Na lio 3, ns discutimos o modo de operao conectada para interagir com a fonte de
dados utilizando o objeto OracleCommand. Na lio 4, ns aprendemos a ler dados
rapidamente com OracleDataReader. Esta lio mostra como fazer algo parecido
utilizando com DataSet e OracleDataReader.
Um DataSet um depsito de dados em memria que pode armazenar diversas tabelas.
DataSets apenas armazenam dados e no interagem com fontes de dados reais, como
bancos de dados. o OracleDataAdapter que gerencia as conexes com as fontes de
dados. O OracleDataAdapter abre a conexo apenas quando necessrio e fecha assim que
que a tarefa seja completada. Por exemplo, o OracleDataAdapter faz o seguinte quando
preenche um DataSet com dados:
1. Abre a conexo com a fonte de dados
2. Recupera dados e os insere em um DataSet
3. Fecha a conexo
E isto o que ele faz quando atualiza a fonte de dados com as mudanas do DataSet:
1. Abre a conexo com a fonte de dados
2. Grava as mudanas do DataSet na fonte
3. Fecha a conexo
Entre as operaes de preencher o DataSet e atualizar a fonte, as conexes com a fonte
de dados esto fechadas e voc est livre para ler, escrever, apagar e atualizar dados
como quiser no DataSet. Essa a mecnica para se trabalhar com dados desconectados.
Uma vez que as aplicaes utilizam conexes apenas quando necessrio, elas se tornam
mais escalveis.
Alguns cenrios ilustram o porque de voc usar dados desconectados: pessoas
trabalhando sem conectividade de rede, e quando voc quer deixar web sites mais
escalveis.
Excees nesses cenrios acima so aquelas situaes onde h atualizao de dados.
Voc precisa fazer uma deciso, baseada na natureza de como os dados sero utilizados.
Use dados desconectados quando sua informao normalmente utilizada mais para
leitura, isto , seus dados no costumam se modificar muito durante o perodo de tempo
que voc espera ficar com eles. Mas se voc precisar de uma quantidade grande de
dados, talvez voc queira utilizar um OracleDataReader, que oferece uma maneira sem
cache de memria para ler de uma fonte de dados. Realmente, so os requisitos da
aplicao que diro qual deve ser a sua estratgia.
Criando um objeto DataSet

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 23

Tu t o r i a l d e A D O . N E T

No h nada de especial em inicializar um DataSet. Voc cria uma nova instncia como
qualquer outro objeto:
DataSet dsHr = new DataSet();
O construtor de DataSet no precisa de nenhum parmetro. No entanto, h uma
sobrecarga do construtor que aceita o nome do DataSet como parmetro. Ele utilizado
quando voc deseja serializar os dados em XML. J que este no um requisito do
exemplo, eu o deixei de fora.
Neste momento voc ter um DataSet vazio, e voc vai querer preench-lo com dados.
Criando um OracleDataAdapter
O OracleDataAdapter encapsula nele um conjunto de comandos e uma conexo,
utilizados para ler e escrever dados. Voc inicializa um objeto OracleDataAdapter com
uma string de comando SELECT e um objeto de conexo:
OracleDataAdapter daJobs = new OracleDataAdapter(
select job_id, job_title from hr.employees, conn);
O cdigo acima cria um novo OracleDataAdapter, daJobs. A declarao SQL especifica
que dados sero lidos da fonte e gravados no DataSet. O objeto OracleConnection conn,
deveria j estar inicializado, mas no aberto. responsabilidade do OracleDataAdapter
abrir e fechar a conexo quando necessrio.
Como indicado anteriormente, o OracleDataAdapter contm todos os comandos
necessrios para interagir com a fonte de dados. O cdigo mostra como especificar a
declarao de SELECT, mas no mostrou como inserir, atualizar e apagar dados. Estes
so adicionados depois que o OracleDataAdapter inicializado.
H duas maneiras de configurar os comandos UPDATE, INSERT e DELETE: via
propriedades do prprio OracleDataAdapter, ou com um OracleCommandBuilder. Nesta
lio, vou mostrar como utilizar o OracleCommandBuilder. Em uma lio posterior
mostrarei como utilizar as propriedades, o que d mais trabalho, mas tem mais
flexibilidade do que o OracleCommandBuilder. assim que se gera os comandos com
OracleCommandBuilder:
OracleCommandBuilder commandBuilder = new OracleCommandBuilder(daJobs);
Note no cdigo acima que o OracleCommandBuilder inicializado com um nico
parmetro,
que

o
objeto
OracleDataAdapter
j
criado.
Ele
diz
ao
OracleCommandBuilder em que OracleDataAdapter ser criado os comandos. O
OracleCommandBuilder ir ler a declarao SELECT do OracleDataAdapter, inferir os
comandos de insero, remoo e atualizao, e atribui esses comandos s propriedades
InsertCommand, DeleteCommand e UpdateCommand do OracleDataAdapter.
Como mencionado anteriormente, o OracleCommandBuilder tem limitaes. Ele funciona
quando voc tem uma declarao SELECT simples em uma tabela apenas. No entanto, se
voc precisa fazer um join de duas ou mais tabelas, ou usar uma stored procedure para
retornar dados, ele no vai funcionar. Ser descrito uma alternativa para realizar estas
tarefas mais a frente.
Preenchendo o DataSet

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 24

Tu t o r i a l d e A D O . N E T

Depois que voc tem instncias de DataSet e OracleDataAdapter, voc pode preencher
um DataSet. Isso feito utilizando-se o mtodo Fill() do OracleDataAdapter:
daJobs.Fill(dsHr, Jobs);
O mtodo Fill(), como mostrado acima, possui dois parmetros: o objeto DataSet que
ser preenchido e uma string indicando um nome de tabela. O DataSet precisa estar
instanciado antes de se tentar preench-lo com dados. O segundo parmetro o nome
da tabela que ser criada no DataSet com os dados trazidos pelo OracleDataAdapter.
interessante que voc nomeie a tabela com um nome significativo, para que voc consiga
identific-la depois.
O mtodo Fill() tem uma sobrecarga que aceita apenas o DataSet. Neste caso, a tabela
ter o nome padro como Table1, para a primeira tabela. O nmero do nome ser
incrementado de acordo com a quantidade de vezes que voc executa o mtodo Fill().
Usando o DataSet
DataSets so popularmente utilizados com o controle (Windows ou Web) DataGrid.
assim que voc associa um DataSet ao DataGrid:
dgJobs.DataSource = dsHr;
dgJobs.DataMember = Jobs;
A primeira coisa que voc faz, no cdigo acima, atribuir o DataSet propriedade
DataSource do DataGrid. Isso faz com que o DataGrid saiba de onde buscar os dados. Se
voc s fizer isso, o DataGrid mostrar um sinal de mais (+) e permitir que voc
navegue por todas as tabelas do DataSet. Para especificar exatamente que tabela usar,
configure a propriedade DataMember do DataGrid com o nome da tabela. Neste exemplo,
usamos o nome Jobs, que o nome configurado no momento em que foi feito o Fill()
do OracleDataAdapter. por isso que gostamos de especificar o nome da tabela: o cdigo
fica mais legvel.
Atualizando as mudanas
Depois que as modificaes foram feitas no DataSet, voc vai querer atualizar sua fonte
de dados. O cdigo seguinte mostra como utilizar o mtodo Update() do
OracleDataAdapter para atualizar as modificaes no banco de dados:
daJobs.Update(dsHr, Jobs);
O mtodo Update() acima chamado pela instncia de OracleDataAdapter que gerou os
dados contidos no DataSet que queremos atualizar. O segundo parmetro de Update()
a tabela de dsHr que queremos atualizar. A tabela contm os dados que foram
modificados e a instncia de OracleDataAdapter contm os comandos de insero,
atualizao e remoo utilizados para salvar as mudanas.
Colocando tudo junto
At agora, voc viu partes de cdigo utilizados em gerenciamento de dados
desconectados. O que voc precisa realmente saber como implementar isso em uma
aplicao. A listagem 5.1 mostra como os trechos de cdigo mostrados como exemplo
podem ser usados em uma aplicao.
Listagem 5.1: Implementando uma estratgia que usa dados desconectados
using System;
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 25

Tu t o r i a l d e A D O . N E T

using
using
using
using

System.Data;
System.Data.OracleClient;
System.Drawing;
System.Windows.Forms;

namespace Tecnomapas.Tutoriais.AdoNet
{
class DisconnectedDataForm : Form
{
private OracleConnection conn;
private OracleDataAdapter daJobs;
private DataSet dsHr;
private DataGrid dgJobs;
private const string TableName = "Jobs";
// Inicializa o Form com um DataGrid e um Button
public DisconnectedDataForm()
{
// Preenche o DataSet
InitData();
// Configura o DataGrid
dgJobs = new DataGrid();
dgJobs.Location = new Point(5, 5);
dgJobs.Size = new Size(this.ClientRectangle.Size.Width 10, this.ClientRectangle.Height - 50);
dgJobs.DataSource = dsHr;
dgJobs.DataMember = TableName;
// Cria um boto de atualizar
Button btnUpdate = new Button();
btnUpdate.Text = "Atualizar";
btnUpdate.Location = new Point(
this.ClientRectangle.Width/2 - btnUpdate.Width/2,
this.ClientRectangle.Height - (btnUpdate.Height

10));

btnUpdate.Click += new EventHandler(btnUpdateClicked);

// Faa os controles aparecerem no Form


Controls.AddRange(new Control[] { dgJobs, btnUpdate });

// Configura os objetos ADO.NET


public void InitData()
{
// Inicializa a conexo
conn = new OracleConnection(
"Data
Id=fsomalia;Password=654321");

Source=apisora2;User

// 1. Incializa um novo DataSet


dsHr = new DataSet();
// 2. Inicializa o OracleDataAdapter
daJobs = new OracleDataAdapter("select job_id, job_title
from hr.jobs", conn);
alterao
(daJobs);

//

3.

Configura

os

OracleCommandBuilder

comandos
cmdBldr

de
new

insero,

remoo

OracleCommandBuilder

// 4. Preenche o DataSet
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 26

Tu t o r i a l d e A D O . N E T

daJobs.Fill(dsHr, TableName);

// O boto de atualizar foi clicado


public void btnUpdateClicked(object sender, EventArgs e)
{
// Escreve as mudanas do DataSet no banco de dados
daJobs.Update(dsHr, TableName);
}

// Inicia o Form Windows


static void Main()
{
Application.Run(new DisconnectedDataForm());
}

O mtodo InitData() da listagem 5.1 contm os mtodo necessrios para configurar o


OracleDataAdapter e o DataSet. Note que os objetos de dados so definidos a nvel de
classe (como campos da classe), assim eles podem ser usados por todos os mtodos. A
propriedade DataSource do DataGrid configurada no construtor da classe principal da
aplicao. Sempre que o usurio clica no boto Atualizar, o mtodo Update() de
OracleDataAdapter chamado no gerenciador do evento Click do boto, levando as
modificaes para o banco de dados.
Sumrio
DataSets armazenam mltiplas tabelas e podem ser usados e reutilizados em memria.
O OracleDataAdapter permite fazer a ponte entre o DataSet e a fonte de dados, ao
preencher o DataSet e gravar as modificaes deste na fonte de dados. Voc no precisa
se preocupar em abrir e fechar uma conexo com o banco de dados quando usa o
OracleDataAdapter. Use o mtodo Fill() para trazer dados da fonte e coloc-los em um
DataSet, e use Update() para salvar as modificaes do DataSet em uma fonte de dados.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 27

Tu t o r i a l d e A D O . N E T

Lio 6: Adicionando parmetros em comandos

Esta lio mostra como voc pode adicionar parmetros a um comando. Objetivos:

Entender o que um parmetro


Entender o porqu de se utilizar um parmetro
Aprender a criar parmetros
Aprender a atribuir parmetros a comandos

Introduo
Quando voc trabalha com dados, muitas vezes voc deseja filtrar as informaes que
so trazidas por um comando de seleo. Tipicamente, voc faz isso adicionando uma
clusula where na string de comando do SELECT.
Como voc sabe, uma consulta SQL atribuda a um objeto OracleCommand
simplesmente uma string. Ento, se voc desejar modificar um filtro ao seu comando,
voc poderia alterar a string do comando. Mas isso voc no deveria fazer. A vai um
exemplo:
// Nunca faa isso!
OracleCommand cmd = new OracleCommand(select * from hr.employees e where
e.first_name like '+ filtro +', conn);
Nunca construa uma consulta assim! A varivel que contm o filtro, filtro, tipicamente
recuperada de um TextBox colocado no form da aplicao (Windows ou Web). Qualquer
coisa escrita neste TextBox enviada como comando para o banco de dados. Isso
convida qualquer hacker a tentar quebrar seu programa. Na pior das hipteses, ele pode
ganhar o controle da sua mquina.
Alm disso, h uma questo de performance. Para cada filtro diferente digitado pelo
usurio, uma string de comando diferente criada e enviada para o banco de dados. Isso
significa que cada nova string passar por uma anlise verificando sintaxe, permisses e
planejamento de consulta, o que demanda tempo. O banco de dados Oracle faz cache
automtico das consultas j analisadas, e assim, o tempo de anlise para novas
consultas que utilizam a mesma string suprimido. Mas isso s acontece se a string for a
mesma.
Ao invs de criar uma string de comando dinamicamente para alterar o filtro, use
parmetros. Qualquer coisa colocada em um parmetro e tratado como dado, e no parte
da consulta SQL, o que deixa o comando mais seguro. Alm disso a string de comando
nunca muda, e o banco de dados pode tomar vantagem do cache de consultas.
Para utilizar consultas parametrizadas, execute estes trs processos:
1. Construa o comando OracleCommand usando uma string com parmetros
2. Declare um objeto OracleParameter, atribuindo os valores necessrios
3. Adiciona o objeto OracleParameter ao OracleCommand, utilizando a propriedade
Parameters
As sees seguintes mostra esse processo passo a passo.
Preparando um objeto OracleCommand com parmetros

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 28

Tu t o r i a l d e A D O . N E T

O primeiro passo ao usar parmetros em comandos SQL construir uma string que tenha
os parmetros. Estes lugares de parmetros so preenchidos com valores quando o
comando executado. A sintaxe para se fazer isso em um comando de Oracle colocar
dois-pontos (:) antes do identificador do parmetro. Dessa forma:
// 1. Escreve um comando parametrizado
OracleCommand cmd = new OracleCommand(select * from hr.employees e where
e.first_name like :filtro, conn);
No construtor do comando acima, o primeiro argumento contm a declarao do
parmetros, :filtro. Neste exemplo usado apenas um parmetro, mas voc pode ter
quantos parmetros forem necessrios. Cada parmetro precisa combinar com um objeto
OracleParameter que vai ser criado e atribudo ao OracleCommand.
Declarando objetos OracleParameter
Cada parmetro em uma declarao SQL precisa ser definido. Este o objetivo do tipo
OracleParameter. Seu cdigo precisa definir cada parmetro declarado na string de
comando. O cdigo seguinte define o parmetro :filtro declarado no cdigo anterior:
// 2. Define parmetros usados com objeto de comando
OracleParameter param = new OracleParameter();
param.ParameterName = filtro;
param.Value = filtro;
Note que o nome do parmetro precisa ser exatamente igual ao declarado na string de
comando, mas sem os dois-pontos. Voc tambm precisa especificar um valor para o
parmetro. Sem valor, o banco de dados retornar um erro dizendo que nem todas as
variveis so limitadas. Quando o comando executado, o parmetro substitudo pelo
valor.
Associando um objeto OracleParameter a um OracleCommand
Para cada parmetro definido, voc precisa associ-lo ao objeto de comando. Dessa
forma voc est dizendo ao cdigo que valor utilizar para aquele parmetro declarado no
comando. O seguinte cdigo mostra como fazer isso.
// 3 Adiciona um novo parmetro ao objeto de comando
cmd.Parameters.Add(param);
A instncia de OracleCommand o argumento do mtodo Add() da propriedade
Parameters.
Colocando tudo junto
Voc j sabe como usar um OracleCommand e um OracleDataReader. O programa a
seguir mostra como trabalhar com objetos OracleParameter. Portanto, tudo deve parecer
familiar para voc, com exceo das novas partes adicionadas nesta lio.
Listagem 6.1: Adicionando parmetros em consultas
using System;
using System.Data;
using System.Data.OracleClient;
namespace Tecnomapas.Tutoriais.AdoNet
{

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 29

Tu t o r i a l d e A D O . N E T

class ParamDemo
{
static void Main()
{
OracleConnection conn
= null;
OracleDataReader reader = null;
string filtro = "%John%";
try
{
// Inicializa e abre a conexo
conn = new
OracleConnection("Data
Id=fsomalia;Password=654321");
conn.Open();

Source=apisora2;User

// 1. Escreve um comando parametrizado


OracleCommand cmd = new OracleCommand(
"select
e.first_name,
e.last_name
hr.employees e where e.first_name like :filtro", conn);
//

comando

2.

Define

parmetros

usados

com

from

objeto

de

OracleParameter param = new OracleParameter();


param.ParameterName = "filtro";
param.Value = filtro;
//

comando

Adiciona

um

novo

parmetro

ao

objeto

de

cmd.Parameters.Add(param);
// Obtem os dados
reader = cmd.ExecuteReader();
// Imprime cada registro
while(reader.Read())
{
Console.WriteLine("{0} {1}",
reader["first_name"],
reader["last_name"]);
}

}
finally
{
// Fecha reader
if (reader != null)
{
reader.Close();
}
// Fecha conexo
if (conn != null)
{
conn.Close();
}

}
Console.Read();

O cdigo na listagem 6.1 simplesmente recupera os registros de cada empregado que


tenha primeiro nome John. Isso feito de forma mais segura e rpida utilizando
parmetros.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 30

Tu t o r i a l d e A D O . N E T

Sumrio
Voc deve usar parmetros para fazer filtros em comandos de maneira segura. O
processo de utilizar parmetros contm trs passos: criar um comando com uma string
parametrizada, definir um OracleParameter para cada parmetro declarado, e associar os
parmetros ao objeto de comando. Quando o comando executado, os parmetros so
substitudos pelos seus valores.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 31

Tu t o r i a l d e A D O . N E T

Lio 7: Usando Stored Procedures

A lio mostra como usar stored procedures em seu cdigo de acesso a dados. A vai os
objetivos desta lio:

Aprender a modificar o objeto OracleCommand para executar stored procedures


Entender como usar parmetros com stored procedures

Introduo
Uma stored procedure uma rotina pr-definida e reutilizvel armazenada no banco de
dados. O banco de dados Oracle compila as stored procedures, o que as deixa mais
eficientes para uso. Portanto, ao invs de construir consultas com seu cdigo C#, voc
poderia conseguir alguma performance ao utilizar stored procedures. As seguintes sees
iro mostrar como o objeto OracleCommand pode acionar uma stored procedure.
Adicionalmente, voc ver mais um motivo de se utilizar parmetros.
Executando uma stored procedure
Alm dos comandos que fazem seleo e alterao de dados no banco, o objeto
OracleCommand pode ser utilizado para executar stored procedures. H duas coisas que
precisam acontecer: fazer com que o objeto de comando saiba qual stored procedure
chamar e fazer o objeto de comando saber que o comando uma stored procedure. O
cdigo que faz tudo isso o seguinte:
// 1. Cria um objeto de comando identificando a stored procedure
OracleCommand cmd = new OracleCommand(hr.secure_dml, conn);
// 2. Configura o objeto de comando para executar uma stored procedure
cmd.CommandType = CommandType.StoredProcedure;
Quando voc declara o comando, voc passa hr.secure_dml como parmetro. Este o
nome de uma stored procedure com esquema de exemplo HR do banco de dados Oracle.
O segundo parmetro um OracleConnection que indica o banco de dados a executar a
stored procedure. Ou seja, o construtor de OracleCommand o mesmo que voc j
estava acostumado.
O segundo comando diz para o objeto OracleCommand que o tipo de comando que ser
executado uma stored procedure. A interpretao padro, se voc no configurar
CommandType, identificar o comando como uma string SQL. Quando voc diz que
CommandType CommandType.StoredProcedure, voc diz que o contedo de
CommandText o nome de uma stored procedure, e no um comando SQL.
Enviando parmetros para uma stored procedure
A forma de usar parmetros em stored procedures a mesma que em strings de
comando SQL. O cdigo seguinte faz isso:
// 1. Cria um comando que identifica uma stored procedure
OracleCommand cmd = new OracleCommand("calc_double", conn);
// 2. Configura o objeto de comando para executar uma stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. Adiciona parmetros ao comando
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 32

Tu t o r i a l d e A D O . N E T

cmd.Parameters.Add(new OracleParameter("value1", OracleType.Number));


cmd.Parameters.Add(new OracleParameter("value2", OracleType.Number));
cmd.Parameters["value1"].Value = 3;
cmd.Parameters["value2"].Direction = ParameterDirection.Output;
O construtor do comando cria um comando para uma stored procedure chamada
calc_double. Este o cdigo de calc_double:
create procedure hr.calc_double(value1 in number, value2 out number) is
begin
value2 := value1*2;
end;
Voc percebe uma quantidade razovel de novas sintaxes no passo 3. Vamos explic-las
uma a uma. Os dois primeiros comandos do passo 3 definem dois parmetros. Esses dois
parmetros, value1 e value2, so justamente o nome dos parmetros da stored
procedure calc_double.
Note que a sintaxe do mtodo Add() de Parameters j instancia um novo parmetro,
utilizando um dos construtores de OracleParameter. Este construtor de OracleParameter
recebe dois valores: o nome do parmetros (value1, por exemplo) e o tipo do
parmetro. O tipo do parmetro definido por um enumerado chamado OracleType, que
contm todos os tipos bsicos do banco de dados Oracle. No caso dos dois parmetros
value1 e value2, uma vez que eles foram declarados como NUMBER na stored
procedure, indicamos o tipo OracleType.Number.
O comando seguinte apenas define um valor para o parmetro de entrada. Note que o
parmetro value1 j foi adicionado lista Parameters, e portanto, podemos utilizar o
indexador de Parameters para especific-lo.
O ltimo comando o mais interessante aqui. Uma vez que o parmetro value2 foi
declarado na stored procedure como out, ns precisamos definir o parmetro para nosso
comando como somente sada. Isso feito definindo a propriedade Direction do
parmetro com um dos valores do enumerado ParameterDirection. value2 no precisa
de valor, uma vez que ele no poder ser lido dentro do escopo da stored procedure, j
que ele somente escrita.
Uma stored procedure normalmente declara um parmetro de sada quando ela precisa
mandar informaes ao programa chamador, quando ela termina. Portanto, comum que
ns queiramos ler o valor enviado pela stored procedure depois que ela executada. Para
ler o valor da stored procedure, apenas acessamos a propriedade Value do parmetro,
depois que o comando executado. Assim:
// Executa o comando
cmd.ExecuteNonQuery();
// Obtem o valor do parmetro de sada
Console.WriteLine("Valor {0}", cmd.Parameters["value2"].Value);
Colocando tudo junto
O cdigo na listagem 7.1 mostra um programa que utiliza stored procedures. H dois
mtodos separados: um acessa uma stored procedure sem parmetros, outra acessa
stored procedures com parmetros.
Listagem 7.1: Executando stored procedures
using System;
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 33

Tu t o r i a l d e A D O . N E T

using System.Data;
using System.Data.OracleClient;
namespace Tecnomapas.Tutoriais.AdoNet
{
class StoredProcDemo
{
static void Main()
{
StoredProcDemo spd = new StoredProcDemo();
// Roda uma stored procedure simples
spd.RunStoredProc();
// Roda uma stored procedure com parametros
spd.RunStoredProcParams();
}

Console.Read();

// Roda uma stored procedure simples


public void RunStoredProc()
{
OracleConnection conn = null;
simples:\n");

Console.WriteLine("\nExecutando
try
{

uma

stored

procedure

// Cria e abre uma conexo


conn = new OracleConnection(
"Data Source=apisora3;User Id=hr;Password=hr");
conn.Open();
// 1. Cria um comando que identifica uma stored

procedure

OracleCommand
("hr.secure_dml", conn);
uma stored procedure

cmd

new

OracleCommand

// 2. Configura o objeto de comando para executar


cmd.CommandType = CommandType.StoredProcedure;
// Executa o comando
cmd.ExecuteNonQuery();

}
finally
{
if (conn != null)
{
conn.Close();
}
}

// Roda uma stored procedure com parametros


public void RunStoredProcParams()
{
OracleConnection conn = null;
aqui

// Tipicamente obtido do usurio, mas vamos configurar

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 34

Tu t o r i a l d e A D O . N E T

int valor = 3;
parametros:\n");

Console.WriteLine("\nExecutando uma stored procedure com


try
{

procedure
("calc_double", conn);
uma stored procedure

OracleType.Number));
OracleType.Number));

// Cria e abre uma conexo


conn = new OracleConnection(
"Data Source=apisora3;User Id=hr;Password=hr");
conn.Open();
// 1. Cria um comando que identifica uma stored
OracleCommand

cmd

new

OracleCommand

// 2. Configura o objeto de comando para executar


cmd.CommandType = CommandType.StoredProcedure;
// 3. Adiciona parmetros ao comando
cmd.Parameters.Add(new
OracleParameter("value1",
cmd.Parameters.Add(new

OracleParameter("value2",

cmd.Parameters["value1"].Value = 3;
cmd.Parameters["value2"].Direction
ParameterDirection.Output;

// Executa o comando
cmd.ExecuteNonQuery();
// Obtem o valor do parmetro de sada
Console.WriteLine("Valor

{0}",
cmd.Parameters

["value2"].Value);
}
finally
{
if (conn != null)
{
conn.Close();
}
}
}
}
}

O mtodo RunStoredProc() na listagem 7.1 simplesmente roda uma stored procedure


chamada secure_dml. Essa stored procedure gera uma exceo de banco de dados se
no for rodada em horrio comercial. J o mtodo RunStoredProcParams() chama uma
stored procedure que utiliza dois parmetros, sendo um deles de sada. O resto do cdigo
deve ser familiar para voc.
Sumrio
Para executar stored procedures, voc especifica o nome da stored procedure como
primeiro parmetro do construtor de um OracleCommand e configura a propriedade
CommandType para CommandType.StoredProcedure. Voc tambm pode enviar
parmetros para stored procedures como voc faz com consultas SQL. Por fim, voc
tambm aprendeu novas maneiras de manipular parmetros de comandos e aprendeu a

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 35

Tu t o r i a l d e A D O . N E T

receber valores de stored procedures. Os parmetros de sada podem ser utilizados tanto
em stored procedures quando em consultas SQL.

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 36

Tu t o r i a l d e A D O . N E T

Lio 8: Trabalhando com transaes

Esta lio mostra como trabalhar com transaes em ADO.NET. Os objetivos especficos
so os seguintes:

Entender o que so transaes


Aprender como iniciar transaes em ADO.NET
Aprender a confirmar ou descartar uma transao

Introduo
Em certos momentos de sua programao ADO.NET, voc encontrar situaes onde voc
precisa executar vrios comandos como uma unidade. Ou seja, voc precisar que todos
os comandos enviados para o banco de dados executem corretamente, ou no executar
nenhum.
Um exemplo bastante comum em um sistema de contas financeiras de clientes de um
banco. Quando um cliente deseja fazer uma transferncia monetria de sua conta para a
conta de um outro cliente, duas tarefas precisam ser realizadas: o dbito da quantia
desejada da conta de origem, e o crdito do mesmo valor na conta de destino. Se alguma
coisa dar errada entre um passo e outro (por exemplo, um problema de comunicao de
rede que impede o acesso a uma das contas), voc vai querer desfazer todas as
alteraes realizadas at o momento, ou os clientes iro ficar infelizes (ou felizes!).
Neste caso simples, voc poderia enumerar uma srie de comandos que poderiam evitar
esse tipo de problema. Mas este um caso simples que usa apenas duas tarefas. Em
alguns casos, podem existir bem mais tarefas, e o cdigo para evitar problemas crescer
exponencialmente.
A maioria dos bancos de dados atuais permitem tratar uma srie de comandos como uma
unidade, e dessa forma, ou todos os comandos so executados, ou nenhuma alterao
feita. Isto chamado de transao. Uma transao segue o modelo ACID, que significa:

Atomicidade: os comandos devem ser tratados como unidade. Ou os comandos da


transao so executados, ou nenhuma alterao feita.
Consistncia: no fim da transao, o banco de dados deve estar da mesma forma que
foi encontrado no incio. Nenhuma regra de negcio deve estar violada ao fim da
transao. Se alguma regra for violada, a transao descartada e nenhuma alterao
feita por ela escrita no banco
Isolamento: as operaes de uma transao so separadas das operaes de outras
transaes. Uma transao v apenas os dados encontrados no incio da transao
mais os dados modificados por ela mesma (isso chamado de estado intermedirio da
transao).
Nenhuma transao tem acesso ao estado intermedirio de outra
transao.
Durabilidade: quando uma transao termina, seu estado intermedirio gravado no
banco de dados, para que outras transaes possam acess-los.

Criando transaes com ADO.NET


Para trabalhar com transaes, voc precisa completar trs tarefas:
1. Obter uma instncia de OracleTransaction a partir do objeto de conexo
2. Configurar os comandos para utilizarem a transao obtida

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 37

Tu t o r i a l d e A D O . N E T

3. Executar os comandos
4. Aceitar ou rejeitar as modificaes da transao
A listagem 8.1 mostra como fazer isso, em um programa operacional.
Listagem 8.1: Utilizando transaes
using System;
using System.Data;
using System.Data.OracleClient;
namespace Tecnomapas.Tutoriais.AdoNet
{
class StoredProcDemo
{
static void Main()
{
OracleConnection conn = null;
OracleTransaction trans = null;
try
{

Id=hr;Password=hr");

// Cria e abre uma conexo


conn = new
OracleConnection("Data

Source=apisora2;User

conn.Open();
//1. Obtem transao a partir do objeto de conexo
trans = conn.BeginTransaction();
//2. Configura comando a ser utilizado na transao
OracleCommand cmd = new OracleCommand();
cmd.Transaction = trans;
//Configura e executa primeiro comando da transao
cmd.CommandText = "insert into hr.countries c "+
"(c.country_id, c.country_name, c.region_id)"+
" values ('PT', 'Portugal', 1) ";
cmd.ExecuteNonQuery();

//Configura e executa segundo comando da transao


cmd.CommandText = "insert into hr.locations l "+
"(l.location_id,
l.street_address,
l.city,
l.state_province, l.country_id) "+
"values (3300, 'Minho 222', 'Lentiscais',
'Castelo Branco', 'PT') ";
cmd.ExecuteNonQuery();
// 3. Aceita as mudanas se tudo correu bem
trans.Commit();
}
catch (Exception)
{
trans.Rollback();
}
finally
{
if (conn != null)
{
conn.Close();
}
Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 38

Tu t o r i a l d e A D O . N E T

}
}
}

Console.Read();

No programa da listagem 8.1, dois comandos so executados dentro de uma transao.


Ns precisamos inserir um novo local no sistema HR. Mas este novo local fica em
Portugal, e este pas no est no sistema. Portanto, precisamos inserir Portugal tambem.
Por isso, fazemos o seguinte. O primeiro comando insere um novo pas na tabela de
pases do esquema HR. O segundo comando insere um novo local no esquema HR. Como
o novo local depende do novo pas que est sendo inserido, ns precisamos ter certeza
de que o pas foi inserido antes de inserir o local. Se ocorrer alguma falha na insero do
pas (como duplicao da chave primria, por exemplo), o fluxo do programa cai no bloco
de tratamento de exceo e a transao rejeitada com o mtodo Rollback().
Da mesma forma, no interessante para ns inserir apenas o pas e no o local. Por
tanto, se ocorrer algum problema na insero do local, o fluxo do programa cai no bloco
de tratamento de exceo e a transao rejeitada. Assim, todas as alteraes dentro da
transao so desfeitas, inclusive a insero do novo pas.
Se os dois comandos so executados com sucesso, o procedimento termina com o
mtodo Commit() da transao, e todas as alteraes so disponibilizadas para outros
usurios do banco de dados.
Sumrio
Nesta lio voc aprendeu a trabalhar com transaes. Um transao permite isolar e
tratar como unidade vrios comandos de banco de dados. Uma transao pode ser
manipulada em ADO.NET com o objeto OracleTransaction. Voc precisa realizar alguns
passos para gerenciar uma transao. A principal terminar a transao quando voc
no mais precisar dela, executando um dos seus mtodos Commit() ou Rollback().

Cuiab, 25 de Julho de 2005, 10:11

Documento: TIPX-1

Pgina 39

Potrebbero piacerti anche