Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
N E T
NPDS
TUTORIAL
DE
ADO.NET
Documento: TIPX-1
Pgina 1
Tu t o r i a l d e A D O . N E T
ndice
Documento: TIPX-1
Pgina 2
Tu t o r i a l d e A D O . N E T
Documento: TIPX-1
Pgina 3
Tu t o r i a l d e A D O . N E T
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.
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
ODBC
Odbc
OLE DB
OleDb
Oracle
Oracle
SQL
Sql
Borland
Bdp
Documento: TIPX-1
Pgina 4
Tu t o r i a l d e A D O . N E T
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.
Documento: TIPX-1
Pgina 6
Tu t o r i a l d e A D O . N E T
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
Descrio
Server
User Id
Password
Documento: TIPX-1
Pgina 7
Tu t o r i a l d e A D O . N E T
// 2. Abre a conexo
conn.Open();
// 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();
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
Documento: TIPX-1
Pgina 10
Tu t o r i a l d e A D O . N E T
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:
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.
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();
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,
Documento: TIPX-1
Pgina 13
Tu t o r i a l d e A D O . N E T
Source=apisora2;User
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
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)";
Documento: TIPX-1
Pgina 15
Tu t o r i a l d e A D O . N E T
uma conexo
conn);
}
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);
cmd
new
OracleCommand
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
}
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();
Documento: TIPX-1
Pgina 17
Tu t o r i a l d e A D O . N E T
Documento: TIPX-1
Pgina 18
Tu t o r i a l d e A D O . N E T
Esta lio explica como ler dados com um objeto OracleDataReader. A vai os objetivos
da lio:
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
// Imprime os resultados
Console.Write({0,-25}, nome);
Console.Write({0,-20}, sobrenome);
Console.Write({0,-25}, email);
Console.WriteLine();
Documento: TIPX-1
Pgina 20
Tu t o r i a l d e A D O . N E T
rd.SimpleRead();
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
------------
}
Console.Read();
}
finally
{
// 3. Fecha o reader
if (rdr != null)
{
rdr.Close();
}
// Fecha a conexo
if (conn != null)
{
conn.Close();
}
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.
Documento: TIPX-1
Pgina 22
Tu t o r i a l d e A D O . N E T
usando
objetos
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
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
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));
Source=apisora2;User
//
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);
Documento: TIPX-1
Pgina 27
Tu t o r i a l d e A D O . N E T
Esta lio mostra como voc pode adicionar parmetros a um comando. Objetivos:
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
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
{
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
comando
2.
Define
parmetros
usados
com
from
objeto
de
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();
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.
Documento: TIPX-1
Pgina 31
Tu t o r i a l d e A D O . N E T
A lio mostra como usar stored procedures em seu cdigo de acesso a dados. A vai os
objetivos desta lio:
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
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();
Console.WriteLine("\nExecutando
try
{
uma
stored
procedure
procedure
OracleCommand
("hr.secure_dml", conn);
uma stored procedure
cmd
new
OracleCommand
}
finally
{
if (conn != null)
{
conn.Close();
}
}
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");
procedure
("calc_double", conn);
uma stored procedure
OracleType.Number));
OracleType.Number));
cmd
new
OracleCommand
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();
}
}
}
}
}
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.
Documento: TIPX-1
Pgina 36
Tu t o r i a l d e A D O . N E T
Esta lio mostra como trabalhar com transaes em ADO.NET. Os objetivos especficos
so os seguintes:
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:
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");
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();
Documento: TIPX-1
Pgina 38
Tu t o r i a l d e A D O . N E T
}
}
}
Console.Read();
Documento: TIPX-1
Pgina 39