C# - Acessando e obtendo dados com DataReader


Este artigo mostra como acessar um banco de dados e exibir as informações das tabelas usando ADO .NET, mais especificamente a classe DataReader.

A classe DataReader fornece funções similares aos cursores SQL, os quais não são atualmente suportados na plataforma .NET. Dessa forma ela é usada para retornar um fluxo de dados e somente-para-frente e somente-leitura de uma fonte de dados de forma muito eficiente.

Os DataReaders são apropriados quando você precisa simplesmente exibir o resultado de uma consulta em cenários onde as informações não precisam ser atualizadas nem persistidas através de múltiplas requisições.

A classe DataReader é um componente ADO .NET que possui diversos componentes para acesso e manipulação de dados e que possui dois componentes principais:

A seguir temos uma figura mostrando os componentes da arquitetura ADO .NET:

Neste exemplo eu vou acessar o banco de dados Northwind.mdf do banco de dados SQL Server e exibir informações em um projeto Windows Forms usando a linguagem C#.

Este é um artigo para iniciantes e aborda o acesso a dados, a utilização da classe DataReader em um projeto Windows Forms.

Para criar o projeto deste artigo eu vou usar o Visual C# 2010 Express Edition (ele é gratuito).

Abra o Visual C# 2010 Express e crie um novo projeto do tipo Windows Forms Application com o nome acesso_DataReader;

No exemplo deste artigo vamos criar uma interface que permite que usuários efetuem consultas na tabela Products do banco de dados Northwind usando uma consulta com parâmetros e a classe DataReader.

Vamos definir a interface com o usuário no formulário form1.vb conforme o leiaute da figura abaixo:

Os componentes usados a partir da ToolBox foram:

O projeto vai funcionar assim:

  1. O usuário informa na caixa de texto o nome completo ou parcial de um produto que deseja localizar e clica no botão para localizar;
  2. O código executa uma consulta SQL usando parâmetros e obtém um DataReader com as informações exibindo-as no ListBox;

A seguir temos a imagem mostrando a tela principal do programa exibindo informações dos produtos da tabela Products do banco de dados Northwind.mdf;

Observe que basta o usuário digitar um caractere para que produtos iniciados pelo caractere sejam exibidos e que também exibidos o total de produtos localizados para a consulta.

Vejamos como podemos implementar o código para realizar tal tarefa.

Iniciamos definindo os namespaces usados no projeto:

using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Configuration;

Os namespaces System.Data e System.Data.SqlClient nos dão acesso as classes de acesso a dados usadas no projeto : SqlConnection, SqlCommand, SqlDataReader e a propriedade ConnectionState;

O namespace Configuration permite usarmos a classe ConfigurationManager para obter a string de conexão do arquivo App.Config que é exibido abaixo:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
    </configSections>
    <connectionStrings>
        <add name="acesso_DataReader.Properties.Settings.NORTHWNDConnectionString"
            connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\NORTHWND.MDF;Integrated Security=True;Connect Timeout=30;User Instance=True"
            providerName="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

Além de definir o namespace devemos incluir uma referência no projeto a System.Configuration para isso clique com o botão direito do mouse sobre o nome do projeto e selecione Add Reference;

Em seguida selecione na aba .NET a opção System.Configuration e clique Ok;

Agora vamos definir as variáveis objeto usadas no projeto declarando-as logo após no início do formulário form1::

SqlDataReader rdr = null;
SqlConnection con = null;
SqlCommand cmd = null;

Crie a rotina getConexaoBD no formulário form1 que vai obter a string de conexão do arquivo App.Config usando a classe ConfigurationManager, criar uma nova conexão e retorna a conexão criada:

 private SqlConnection getConexaoBD()
 {
     //obtem a string de conexão do App.Config e retorna uma nova conexao
     string strConexao = ConfigurationManager.ConnectionStrings["acesso_DataReader.Properties.Settings.NORTHWNDConnectionString"].ConnectionString;
     return new SqlConnection(strConexao);
 }

No evento Click do botão para localizar produtos , ao lado da caixa de texto, defina o seguinte código:

      private void btnLocalizar_Click(object sender, EventArgs e)
        {
            try
            {
                con = getConexaoBD();
                con.Open();

                // define o command com a consulta dada e associa a conexão
                string sql = "SELECT ProductID, ProductName, UnitPrice" +
                                  " FROM Products" +
                                  " WHERE (ProductName LIKE @nomeProduto)" +
                                  " ORDER BY ProductID";

                cmd = new SqlCommand(sql);
                cmd.Connection = con;

                // define o parâmetro
                cmd.Parameters.Add(new SqlParameter(
                       "@nomeProduto",                            // o nome do produto 
                       System.Data.SqlDbType.NVarChar, // o tipo do parametro
                       20,                                                  // o tamanho do parametro
                       "ProductName"));                           // o nome da coluna

                // Preenche o parametro com o valor obtido do campo texto
                cmd.Parameters["@nomeProduto"].Value = txtProduto.Text + "%";

                // Executa a cosulta
                rdr = cmd.ExecuteReader();
                // limpa o listbox
                lbProdutos.Items.Clear();
                //define o total de registros como zero
                int nuReg = 0;
                //percorre o leitor e exibe os valores no listbox
                while (rdr.Read())
                {
                    lbProdutos.Items.Add(rdr["ProductID"].ToString() +
                    " - " + rdr["ProductName"].ToString() + " - " + rdr["UnitPrice"].ToString());
                    nuReg++;
                }
                //exibe o total de registros obtidos
                lbltotal.Text = nuReg.ToString() + " Produtos";
                
            }
            catch (Exception ex)
            {
                // mensagem de erro
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // fecha os objetos datareader e connection
                if (rdr != null)
                    rdr.Close();

                if (con.State == ConnectionState.Open)
                    con.Close();
            }
        }

Vamos entender o código usado:

1- Obtemos uma nova conexão usando a função getConexaoBD() e a abrimos:

   con = getConexaoBD();
                con.Open();

2- Definimos uma instrução SQL para retornar o código, nome e preço do produto onde o nome do produto deverá ser igual ao nome informado pelo usuário. Aqui criarmos uma consulta parametrizada onde o parâmetro foi definido como @nomeProduto. Note o sinal @ no início do nome.

A  cláusula LIKE permite efetuar uma consulta irrestrita:

Usando a cláusula LIKE
As vezes os dados que você está desejando filtrar não têm uma ocorrência exata, ou você pretende realizar uma busca mais irrestrita. Para isso devemos usar a cláusula LIKE. Supondo que desejamos filtrar todos os alunos que tenham o nome começado pelas letrar Jos, Através da cláusula LIKE podemos inserir as letras desejadas e a SQL fará uma busca parcial pela string informada: Algo como:
SELECT nome FROM tblalunos WHERE nome LIKE "Jos%"

Isto retornará os possíveis nomes: José , Josué, Josimar, Josias, etc...

Note que usamos o sinal de porcentagem (%) que funciona como um coringa , substituindo os demais caracteres.

A seguir listamos abaixo as principais ocorrências :

Tipo de ocorrência Padrão utilizado na Consulta SQL O retorno da Pesquisa
Múltiplos caracteres b%b bb, bBb, bccccB
Caractere especial b[%]b b%b
Múltiplos caracteres ab% abcdefg, abc

                // define o command com a consulta dada e associa a conexão
                string sql =   "SELECT ProductID, ProductName, UnitPrice" +
                                  " FROM Products" +
                                  " WHERE (ProductName LIKE @nomeProduto)" +
                                  " ORDER BY ProductID";


                cmd = new SqlCommand(sql);
                cmd.Connection = con;

Definimos um objeto Command para a instrução sql definida e especificamos a conexão onde o comando será usado.

3- Definimos o parâmetro a ser usado , seu nome, tipo de dados, tamanho e nome da coluna sobre o qual irá atual e incluímos na coleção Parameters:

                  // define o parâmetro
                      cmd.Parameters.Add(new SqlParameter(
                       "@nomeProduto",                            // o nome do produto
                       System.Data.SqlDbType.NVarChar,   // o tipo de dados do parametro
                       20,                                                  // o tamanho do parametro
                       "ProductName"));                            // o nome da coluna

             
  // Preenche o parametro com o valor obtido do campo texto
                cmd.Parameters["@nomeProduto"].Value = txtProduto.Text + "%"

Ao definir o valor do parâmetro obtemos o valor informado na caixa de texto txtProduto e acrescentamos o curinga '%' a final do texto digitado para ser usado com a cláusula LIKE que já explicamos acima.

4- Executamos a consulta obtendo um DataReader (rdr), e preenchemos o controle ListBox com as informações obtidas:

               // Executa a cosulta
                rdr = cmd.ExecuteReader();
                // limpa o listbox
                lbProdutos.Items.Clear();
            
   //define o total de registros como zero
                int nuReg = 0;
               
//percorre o leitor e exibe os valores no listbox
                while (rdr.Read())
                {
                    lbProdutos.Items.Add(rdr["ProductID"].ToString() +
                    " - " + rdr["ProductName"].ToString() + " - " + rdr["UnitPrice"].ToString());
                    nuReg++;
                }
             
  //exibe o total de registros obtidos
                lbltotal.Text = nuReg.ToString() + " Produtos";

Para obter o total de registros tivemos que usar um artifício.  Quando você usa a classe SqlDataReader ou OleDbDataReader , nao existe nenhuma propriedade RecordCount para indicar quantos registros estão sendo obtidos

O objeto DataReader ou a fonte de dados geralmente sabe quantos registros estão sendo obtidos até que o último registro seja enviado para o cliente.

Para contornar este problema, use um dos seguintes métodos:

Dessa forma cumprimos nosso objetivo e obtemos os registros desejados usando um DataReader. Para melhorar o código sugiro que você crie uma camada e remova o código de acesso a dados do formulário usando as boas práticas.

Pegue o projeto completo aqui:   acesso_DataReader.zip

Eu sei é apenas C#, mas eu gosto...

C# , Simples, simples assim...

Referências:


José Carlos Macoratti