Mostrando postagens com marcador C#. Mostrar todas as postagens
Mostrando postagens com marcador C#. Mostrar todas as postagens

15 de nov. de 2011

Twitter + Silverlight ou WPF

Vamos fazer um cliente de Twitter???

Vamos!

Ebaaa...

image

Ok ok, comemorações a parte vamos iniciar.

A ideia aqui é usar a API do Twitter, fazendo simples requisições web, e aproveitar o potencial do XAML, a linguagem de interface por trás do Silverlight (inclusive do Windows Phone) e do WPF.

Então crie uma aplicação utilizando uma dessas tecnologias chamada de “MeuClienteDeTwitter”.

No exemplo foi utilizado WPF. Nossa UI ficará da seguinte maneira:

clip_image002

No “.xaml” principal/inicial (no caso do WPF o “MainWindow.xaml”), desenhe uma tela, arrastando os controles da Toolbox para a tela, com os seguintes controles:

  • TextBlock: Ao topo servindo de título para a aplicação. Altere a propriedade “Text” (para definir o valor do mesmo) e as propriedades de fonte, para deixar esse texto mais destacado. Esse controle funciona como uma Label do ASP.NET ou Windows Forms.
  • TextBox: Caixa de texto editável. Defina o nome dela como “txtUsuario”, acompanhe na imagem a seguir:
    clip_image004
  • Button: Botão para fazer a requisição e listar os tweets do usuário informado. Defina seu nome como “btnCarregar”.
  • ListBox: Lista de itens. Montaremos um layout para os itens que listaremos. Por hora nomeie-o como “lstConteudo”, e deixe seu fundo transparente, como na imagem abaixo:
    clip_image006

Curiosidade: O controle Label existe tanto no WPF como no Silverlight. Mas ele é um ContentControl, o que significa que ele pode conter “qualquer coisa” dentro delae não ficando limitado somente a texto puro e simples. Podemos adicionar um vídeo e imagem dentro da mesma Label, por exemplo. Como nesse exemplo queremos apenas texto para o título, optei pelo TextBlock.

Uma coisa importante quando definimos layout de telas com XAML é ficar atento ao painel de layout. Pois todos os controles são aninhados e organizados em um ou mais painéis. Há vários painéis, cada um com uma forma de organizar o layout diferente. Nesse caso, todos esses controles ficam dentro de uma Grid.

Essa Grid “não tem nada haver” com as conhecidas “DataGrids”, que montam tabelas com linhas e colunas proveniente de uma coleção de dados.

A Grid do XAML é um painel que se orienta por distancia das margens. Por exemplo: se colocarmos um botão em uma Grid, e definirmos ele com uma margem de 20 pixels na esquerda e 20 pixels na direita, não interessa o tamanho da janela ou o quanto ela for redimensionada, o controle se adaptará para manter a distancia das margens, sempre em 20 pixels próximo as bordas laterais.

A Grid pode ser dividida, criando bordas internas. Nesse exemplo, foi definida uma borda logo abaixo do botão e do campo de texto, para separar a ListBox dos demais controles. Assim, após colocar a ListBox na parte inferior, defini as margens dela como zero para todos os lados, logo ela acompanhará o tamanho da janela tanto em largura como em altura.

Bem, o intuito aqui não é ficar discutindo sobre esses painéis, em outra oportunidade eu falo mais dos mesmos.

Vejamos como ficou o XAML então:

<Window x:Class="MeuClienteDeTwitter.MainWindow"
        xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="484" Width="385">
    <!--Definindo o fundo em gradiente da janela-->
    <Window.Background>
        <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
            <GradientStop Color="LightBlue" Offset="0" />
            <GradientStop Color="White" Offset="1" />
        </LinearGradientBrush>
    </Window.Background>
    <Grid>
        <!--Definindo as linhas da grid para o layout.
        O "*" representa o tamanho que sobrar da jenala,
        após utilizar os 80 da linha de cima-->
        <Grid.RowDefinitions>
            <RowDefinition Height="80" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
       
        <Label Content="Meu Cliente de Twitter" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" FontWeight="Bold" FontSize="16" FontFamily="Verdana" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,46,0,0" Name="txtUsuario" VerticalAlignment="Top" Width="213" />
        <Button Content="Carregar o Twitter" Height="23" HorizontalAlignment="Left" Margin="231,46,0,0" Name="btnCarregar" VerticalAlignment="Top" Width="124" Click="btnCarregar_Click" />
       
        <ListBox Grid.Row="1" Name="lstConteudo" BorderBrush="{x:Null}" Background="{x:Null}">
            <!--Template que define o layout de cada item da ListBox-->
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!--Perceba que foi utilizado um outro painel para definir o layout-->
                    <StackPanel Orientation="Horizontal" Height="132">
                        <Image Source="{Binding UrlFoto}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0" />
                        <StackPanel Width="370">
                            <TextBlock Text="{Binding Usuario}" Foreground="#FFC8AB14" FontSize="28"/>
                            <TextBlock Text="{Binding Conteudo}" TextWrapping="Wrap" FontSize="23"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Para fazer o fundo em gradiente, utilizamos o LinearGradientBrush com duas cores definidas para a Janela.

A primeira linha da Grid, que separa a ListBox dos demais controles do “cabeçalho”, tem 80 pixels de altura, o restante, definido como “*”, fica para a segunda linha que é onde está a ListBox.

Agora vem uma parte importante, a definição do layout dos itens que forem carregados no ListBox. Para isso temos que criar um painel de Layout, dentro do template de dados da ListBox.

Nesse caso o painel de layout utilizado foi o StackPanel, ou painel empilhador. Ele empilha os controles, um sobre o outro, seja na vertical ou na horizontal.

Dentro desse painel, colocamos um controle Image, para exibir a foto do usuário, com altura e largura de 73 pixels. Colocamos também dois TextBlock, um para o nome do usuário, com fonte um pouco maior, e outro para o tweet em si, com a quebra de linha ativada (propriedade “TextWrapping="Wrap"”).

Uma outra curiosidade: se você vem do desenvolvimento Windows Forms e quer uma maneira de organizar layout semelhante aos “bons e velhos” formulários, opte pelo painel chamado Canvas.

Ao analisar o XAML uma coisa deve estar te deixando cmo a pulga atrás da orelha: O que são aqueles “bindings”.

image

O pessoal do ASP.NET deve até desconfiar.

Bem, os bindings são definições de vinculo. Ou seja, nesse caso, passaremos uma lista de objetos para o ListBox. Esses objetos serão do tipo ItemTwitter, que criaremos mais adiante. Ou melhor, vamos cria-lo agora. Clique com o botão direito no projeto > Add > Class. Veja na imagem abaixo:

clip_image008

O nome dela será “ItemTwitter”, o código fonte está abaixo:

namespace MeuClienteDeTwitter
{
    public class ItemTwitter
    {
        public string UrlFoto { get; set; }
        public string Usuario { get; set; }
        public string Conteudo { get; set; }
    }
}

Basicamente três propriedades string estão definidas.

Voltando ao binding, quando passarmos para o ListBox uma lista do tipo ItemTwitter, para cada objeto da lista será criado um item no ListBox. Mas como vincular o layout com as informações dos itens da lista? Definindo um binding no controle e propriedade desejados. No caso da foto, colocaremos no controle Image, na propriedade Source (pois vincularemos a URL da foto do usuário). Nos TextBlocks a propriedade de vinculo será a Text.

No futuro falarei especificamente de binding.

Faltou definir a codificação para tudo funcionar. Então volte para o modo de desing e dê um duplo click no botão, assim será criado o evento click do mesmo.

Em seu click definiremos o seguinte código:

using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Xml.Linq;
 
namespace MeuClienteDeTwitter
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
       
        // -> Método do evento de click do botão para carregar os tweets.
        private void btnCarregar_Click(object sender, RoutedEventArgs e)
        {
            // -> Criamos um objeto que fará uma requisição web para a API do Twitter.
            var requisicao = new WebClient();
 
            // -> Concatenando o nome do usuário digitado na txtUsuario na URL da API do Twitter.
            var url = string.Format("
http://api.twitter.com/1/statuses/user_timeline.xml?screen_name={0}", txtUsuario.Text);
 
            /*
             -> Faremos a requisição web de forma assincrona, ou seja,
             * a requisição é disparada a aplicação não ficará travada até ela responder.
             * Mas quando ela responder, deve responder para a aplicação com um evento.
             * Então temos que definir o evento que ela responderá "requisicao_DownloadStringCompleted".
             * Agora podemos fazer a requisição assincrona, passando a URL da API, atravéz da classe URI.
             */
            requisicao.DownloadStringCompleted += new DownloadStringCompletedEventHandler(requisicao_DownloadStringCompleted);
            requisicao.DownloadStringAsync(new Uri(url));
        }
 
        void requisicao_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // -> Todo o retorno do prossessamento da requisição virá na variável "e".
           
            // -> Verificamos se houve algum erro.
            if (e.Error != null)
                return;
 
            // -> o Retorno da requisição é um XML. Teste no seu navegador para averiguar.
            //      Então fazemos um parse nele para utilizar o LINQ.
            var tweets = XElement.Parse(e.Result);
 
            // -> Usando o LINQ, tranformamos os nós do XML em uma lista de objetos "ItemTwitter"
            var results = from tweet in tweets.Descendants("status")
                          select new ItemTwitter
                          {
                              UrlFoto= tweet.Element("user").Element("profile_image_url").Value,
                              Conteudo = tweet.Element("text").Value,
                              Usuario = tweet.Element("user").Element("screen_name").Value
                          };
 
            // -> Alimenta a ListBox.
            lstConteudo.ItemsSource = results.ToList();
        }
    }
}

Percebam que a API do Twitter nada mais é do que uma chamada HTTP que retorna um XML. Faça o teste no seu Navegador.

Após isso, utilizamos o LINQ para criar objetos, a partir do XML, e com eles alimentamos a ListBox, e está pronto nosso leitor de Tweets.

image

É praticamente a mesma coisa fazer essa App em Silverlight, inclusive coloca-la dentro de seu Windows Phone, veja aqui o Scott Gu fazendo isso:
http://weblogs.asp.net/scottgu/archive/2010/03/18/building-a-windows-phone-7-twitter-application-using-silverlight.aspx

Espero que tenham gostado. Alegre

21 de jul. de 2011

Fonética + SQL Server

1

fonética
(francês phonétique)

s. f.

1. [Linguística]  Parte da linguística que trata dos sons articulados, considerados do ponto de vista físico, acústico e articulatório, como elementos dos vocábulos.

Essa é a definição do dicionário, mas basicamente a fonética é um "ramo" que estuda a pronuncia de uma palavra, visto que há diferenças entre a escrita e a pronuncia. Por exemplo, quantas maneiras podemos escrever o nome Wilham?

Wilian, Willian, Uyliam… Ainda mais no Brasil, e por falar nisso aqui há uma "limitação", a fonética é fortemente vinculada a língua. No brasil o som da letra "i" é um, nos EUA é outro… Ai!

Voltando aos nomes, no exemplo citado o som pode ser "fielmente" definido como "uiliam", então, na teoria, teríamos que bolar algum algoritmo para gerar o fonema da palavra, e nesse caso, independente da maneira como o nome for escrito, o resultado fonético seria o mesmo.

Complicado não!? Mas a boa notícia é que existem inúmeros estudos para gerar essa solução. Um deles é o Soundex. Criado em 1918, por Robert C. Russell e Margaret K. Odell. Esse algoritmo gera uma chave baseada na primeira letra e três números, "calculados" pelas letras na sequencia. Nesse algoritmo, o nosso Willian, viraria W450, e suas variações também.

O SQL Server já implementa nativamente o Soundex. Veja os exemplos a seguir:

2

Mas como "alegria de pobre dura pouco"… Há alguns poréns, primeiramente o Soundex é um algoritmo que funciona muito bem com a língua inglesa. Como disse anteriormente a fonética é extremamente ligada a sua língua. Palavras compostas e alguns casos da língua portuguesa não se dão muito bem com essa implementação do Soundex. Veja:

3

Vamos superar esse #mimimi!? Primeiramente vamos implementar o Soundex em C# e depois implementar adaptações necessárias para a nossa língua.

A base para isso foi tirada da revista Mundo .NET número 26, Casos de sucesso – Pesquisa Fonética em português; Tribunal de Justiça de Mato Grosso do Sul. Nesse caso o tribunal tinha problemas em localizar pessoas no sistema pelo nome. Antes da solução era preciso de informar o nome exato para o sistema buscar as informações.

Vamos definir alguns métodos para a implementação básica do Soundex:

    // -> Obtem o soudex de uma string
private static string GetSoundex(string value)
{
value = value.ToUpper(); // -> Normaliza letras em Maiuscula
var result = new StringBuilder();

foreach (char item in value)
if (char.IsLetter(item)) // -> Limpa String
AddCharacter(result, item); // -> Adiciona um char Soudex

// -> Limpa as exceções geradas
result.Replace(".", string.Empty);
// -> Arruma o tamanho no padrão soudex
// 4 caracteres.
FixLength(result);

return result.ToString();
}

// -> Preenche com 0 nos casos menor q quatro,
// ou pega os 4 primeiros caracteres.
private static void FixLength(StringBuilder result)
{
var length = result.Length;

if (length < 4)
result.Append(new string('0', 4 - length));
else
result.Length = 4;
}

// -> Adiciona o caractere soudex, cuidando para não repetir.
private static void AddCharacter(StringBuilder result, char item)
{
if (result.Length == 0)
{
result.Append(item);
}
else
{
var code = GetSoundexDigit(item);

if (code != result[result.Length - 1].ToString())
result.Append(code);
}
}

// -> Algoritmo de substituição padrão Soudex.
private static string GetSoundexDigit(char item)
{
var charString = item.ToString();

if ("BFPV".Contains(charString))
return "1";
else if ("CGJKQSXZ".Contains(charString))
return "2";
else if ("DT".Contains(charString))
return "3";
else if ("L".Contains(charString))
return "4";
else if ("MN".Contains(charString))
return "5";
else if ("R".Contains(charString))
return "6";
else
return ".";
}




Como a língua portuguesa dispões de muita sujeira e quinquilharia acentos e símbolos, temos de tratá-las com as funções a seguir:




    // -> Recebe várias letras, separadas por virgula, para serem substituídas por uma letra específica.
private static string ReplaceMultiplo(string value, string from, string to)
{
var fromPattern = string.Format("({0})", string.Join(")|(", from.Split(','))).Replace(".", @"\.");
return Regex.Replace(value, fromPattern, to);
}

private static string GetSoundexBR(string value)
{
value = value.ToUpper();
value = ReplaceMultiplo(value, "Á,À,Ã,Â,Ä", "A");
value = ReplaceMultiplo(value, "É,È,Ê,Ë", "E");
value = ReplaceMultiplo(value, "Í,Ì,Î,Ï", "I");
value = ReplaceMultiplo(value, "Ó,Ò,Ö,Õ,Ô", "O");
value = ReplaceMultiplo(value, "Ú,Ù,Û,Ü", "U");
value = ReplaceMultiplo(value, ".,-,", string.Empty);
value = ReplaceMultiplo(value, "0,1,2,3,4,5,6,7,8,9,0", string.Empty);
value = ReplaceMultiplo(value, "Y", "I");
value = ReplaceMultiplo(value, "PH", "F");
value = ReplaceMultiplo(value, "GE", "JE");
value = ReplaceMultiplo(value, "GI", "JI");
value = ReplaceMultiplo(value, "CA", "KA");
value = ReplaceMultiplo(value, "CE", "SE");
value = ReplaceMultiplo(value, "CI", "SI");
value = ReplaceMultiplo(value, "CO", "KO");
value = ReplaceMultiplo(value, "CU", "KU");
value = ReplaceMultiplo(value, "Ç", "S");
value = ReplaceMultiplo(value, "WAS", "WS");
value = ReplaceMultiplo(value, "WA", "VA");
value = ReplaceMultiplo(value, "WO", "VO");
value = ReplaceMultiplo(value, "WU", "VU");
value = ReplaceMultiplo(value, "WI", "UI");

// -> Depois de tratar a lingua portuguesa
// Geramos o soudex padrão.
value = GetSoundex(value);
return value;
}




Agora vem uma parte legal, vamos implementar isso diretamente no SQL Server, usando a CLR do SQL Server, ou seja, a vantagem do SQL Server utilizar o .NET Framework.



Para tal, vamos habilitar a execução da CLR executando os comando a seguir no SQL Server:




sp_configure 'clr', 1
go
RECONFIGURE
go




Em seguida crie no Visual Studio um projeto para o SQL Server:



4



Após isso o Visual Studio pede para se conectar a base onde a CLR será implantada:



SNAGHTML98a862



O projeto já vem estruturado para o SQL Server e com exemplos de teste:



image



Nesse projeto existem várias opções prontas para implementar muitas das funcionalidades do banco de dados. Aqui usaremos uma Function:



image



Cada método que deverá ser função tem que ser decorado com o atributo "[Microsoft.SqlServer.Server.SqlFunction]". Outro ponto importante é que é possível trabalhar com os tipos do SQL Server. Eles são fundamentais para receber entradas e devolver as saídas.



Resta fazer os métodos que serão reconhecidas pelo SQL Server, ou seja, decoradas com o atributo citado acima. A classe final fica assim:




using System.Data.SqlTypes;
using System.Text.RegularExpressions;
using System.Text;
using System.Linq;

public partial class UserDefinedFunctions
{
/*
para ligar o clr no sql server:
sp_configure 'clr', 1
go
RECONFIGURE
go
*/

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString SoundexBR(SqlString value)
{
StringBuilder palavras = new StringBuilder();
value = NormalizarEspacos(value);

var valorNormalizado = value.ToString();

// -> Gera o Soundex de cada palavra da string
valorNormalizado.Split(' ').ToList().ForEach(palavra => palavras.Append(string.Format("{0} ", GetSoundexBR(palavra))));

// -> Retorna o tipo string do SQL Server
return new SqlString(palavras.ToString().Trim());
}

// -> Retira espaços excedentes.
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString NormalizarEspacos(SqlString value)
{
var result = value.ToString().Trim();

while (result.Contains(" "))
result = result.Replace(" ", " ");

return new SqlString(result);
}

// -> Recebe várias letras, separadas por virgula, para serem substituídas por uma letra específica.
private static string ReplaceMultiplo(string value, string from, string to)
{
var fromPattern = string.Format("({0})", string.Join(")|(", from.Split(','))).Replace(".", @"\.");
return Regex.Replace(value, fromPattern, to);
}

private static string GetSoundexBR(string value)
{
value = value.ToUpper();
value = ReplaceMultiplo(value, "Á,À,Ã,Â,Ä", "A");
value = ReplaceMultiplo(value, "É,È,Ê,Ë", "E");
value = ReplaceMultiplo(value, "Í,Ì,Î,Ï", "I");
value = ReplaceMultiplo(value, "Ó,Ò,Ö,Õ,Ô", "O");
value = ReplaceMultiplo(value, "Ú,Ù,Û,Ü", "U");
value = ReplaceMultiplo(value, ".,-,", string.Empty);
value = ReplaceMultiplo(value, "0,1,2,3,4,5,6,7,8,9,0", string.Empty);
value = ReplaceMultiplo(value, "Y", "I");
value = ReplaceMultiplo(value, "PH", "F");
value = ReplaceMultiplo(value, "GE", "JE");
value = ReplaceMultiplo(value, "GI", "JI");
value = ReplaceMultiplo(value, "CA", "KA");
value = ReplaceMultiplo(value, "CE", "SE");
value = ReplaceMultiplo(value, "CI", "SI");
value = ReplaceMultiplo(value, "CO", "KO");
value = ReplaceMultiplo(value, "CU", "KU");
value = ReplaceMultiplo(value, "Ç", "S");
value = ReplaceMultiplo(value, "WAS", "WS");
value = ReplaceMultiplo(value, "WA", "VA");
value = ReplaceMultiplo(value, "WO", "VO");
value = ReplaceMultiplo(value, "WU", "VU");
value = ReplaceMultiplo(value, "WI", "UI");

// -> Depois de tratar a lingua portuguesa
// Geramos o soudex padrão.
value = GetSoundex(value);
return value;
}

// -> Obtem o soudex de uma string
private static string GetSoundex(string value)
{
value = value.ToUpper(); // -> Normaliza letras em Maiuscula
var result = new StringBuilder();

foreach (char item in value)
if (char.IsLetter(item)) // -> Limpa String
AddCharacter(result, item); // -> Adiciona um char Soudex

// -> Limpa as exceções geradas
result.Replace(".", string.Empty);
// -> Arruma o tamanho no padrão soudex
// 4 caracteres.
FixLength(result);

return result.ToString();
}

// -> Preenche com 0 nos casos menor q quatro,
// ou pega os 4 primeiros caracteres.
private static void FixLength(StringBuilder result)
{
var length = result.Length;

if (length < 4)
result.Append(new string('0', 4 - length));
else
result.Length = 4;
}

// -> Adiciona o caractere soudex, cuidando para não repetir.
private static void AddCharacter(StringBuilder result, char item)
{
if (result.Length == 0)
{
result.Append(item);
}
else
{
var code = GetSoundexDigit(item);

if (code != result[result.Length - 1].ToString())
result.Append(code);
}
}

// -> Algoritmo de substituição padrão Soudex.
private static string GetSoundexDigit(char item)
{
var charString = item.ToString();

if ("BFPV".Contains(charString))
return "1";
else if ("CGJKQSXZ".Contains(charString))
return "2";
else if ("DT".Contains(charString))
return "3";
else if ("L".Contains(charString))
return "4";
else if ("MN".Contains(charString))
return "5";
else if ("R".Contains(charString))
return "6";
else
return ".";
}
};




Pronto. Para testar coloque a chamada SQL no arquivo "Test.sql", veja:



image



"Dá o play macaco" #Cruj… E começa o deploy no banco de dados, veja o resultado:



image



Como podemos observar na imagem acima, o fonema é apresentado na janela de output, e como a dll já está instalada no SQL Server podemos testar diretamente nele:



image



Podemos aplicá-la em tabelas  e views normalmente! O desempenho é muito superior comparada a uma implementação onde os dados são recuperados e processados por uma aplicação externa. Códigos .NET rodando diretamente na CLR do SQL Server são muito eficazes.



O Soundex é uma dos estudos disponíveis. Existe também o algoritmo BuscaBR, mas esse fica para uma outra oportunidade Smiley de boca aberta



Obrigado, abraços.

28 de set. de 2010

Um pouco sobre ADO.NET

Como se conectar a um banco de dados com o C# ou outra linguagem da plataforma .NET?

Bem, a maioria das aplicações comerciais desenvolvidas precisam de interação com uma base de dados, para persistir informações, processá-las conforme a necessidade e disponibilizá-las posteriormente.

Dentro do .NET Framework (Plataforma com bibliotecas por trás do C#), temos um subconjunto de bibliotecas, ou um outro framework conhecido como ADO.NET (ActiveX Data Objects). Ele é responsável pela comunicação com alguma base de dados, seja em nível mais primitivo ou robusto.

Como ele faz isso? Através de classes simples e intuitivas, de fácil utilização. Também é possível plugar drivers de conexão com banco de dados nele. Isso o torna bem extensível, ou seja, é possível eu conectar com qualquer base de dados que tenha um driver escrito para o ADO.NET. Na maioria das vezes o fabricante da base de dados acaba fornecendo esse driver.

O driver é o conjunto de bibliotecas necessárias para se comunicar com a base de dados. Apesar dos bancos de dados serem os mais variados possíveis, o ADO.NET impõe um padrão, então apenas alguns detalhes irão mudar nos acessos. No geral o padrão é o mesmo. Mas o ADO.NET expande bastante esse conceito de drivers, e pela imposição do padrão, dentro do .NET eles acabam se tornando nossos Provedores (Providers) de dados.

Os provedores de dados ficam responsáveis por fornecer meio de conexão, leitura e “escrita” em um banco de dados.

Há duas formas básicas (primitivas) de se obter dados de uma consulta a uma base de dados. Uma delas é com DataSet. A outra é com DataReader.

O DataSet é um mapeamento em memória das tabelas, relacionamentos e linhas solicitada na consulta. Ele mantém um controle sobre o estado dos objetos na memória, logo ele tem a capacidade de persistir as mudanças no banco de dados.

O DataReader é um leitor de item a item (linha a linha) retornada da consulta. Ele é mais rápido por não mantém todos os metadados que o DataSet mantém. Porém é somente leitura.

No .NET temos alguns provedores nativos. São eles:

  • SQL Server (System.Data.SqlClient),
  • OLE DB (System.Data.OleDb),
  • ODBC (System.Data.Odbc),
  • Oracle (System.Data.OracleClient – Apenas até o VS 2008/.NET 3.5).

Como já comentado antes, esse provedores são expansíveis, uma prova disso é que a própria Oracle tem um provedor para o ADO.NET (e como eles conhecem melhor o caminho das pedras da base de dados deles, acaba sendo mais eficiente o provedor nativo).

Na figura abaixo é exposto a estrutura básica de um provedor:

Os objetos principais de um provedor são:

  • Connection: Gerencia a conexão com a fonte de dados.
  • Command: Executa comados na fonte de dados, podendo ser utilizado para recuperar um DataSet ou um DataReader.
  • DataReader: Lê as informações (item a item) de uma consulta na fonte de dados.
  • DataAdapter: Utilizado para preencher um DataSet após uma consulta. Como já dito anteriormente, ele também tem a capacidade de replicar a atualização dos dados (após as manipulações necessárias) na fonte de dados.

Observe que o DataSet não está citado acima, pois ele é o mesmo objeto para qualquer provedor. Como? Ele só mantem em memória os dados fornecidos pelo DataAdapter, desconhecendo assim o banco de dados, e deixando essa responsabilidade a cargo do DataAdapter.

Vejamos alguns exemplos de conexão com banco de dados:

image

Importante observar três coisas na figura acima:

A primeira são os namespaces que foram incluídos. Um para cada provedor.

A segunda é a string de conexão. Esta é responsável por localizar o banco de dados e passar as credenciais de conexão. Para compreendermos melhor o conceito de string de conexão, imagine o seguinte: para você se conectar a um site, você tem de informar a URL do mesmo, talvez passar alguns parâmetros pela URL, e em algum momento se autenticar no site. A string de conexão faz isso! para saber mais sobre strings de conexão do ADO.NET acesse: http://www.connectionstrings.com/

A terceira é o fato do padrão de nomenclatura.

Vamos trabalhar com um exemplo simples, porém mais concreto. Após instalar o Visual Studio e SQL server em uma máquina, abra o Visual Studio e localize a window “Server Explorer”:

image

Esta window do Visual Studio gerencia as conexões as bases de dados que você informar. Vamos criar uma nova base de dados no SQL Server, clicando com o Botão direito em “Data Connections” > “Create new SQL Server Database”:

image

image

Configure a janela que aparecer com o nome da sua instância de SQL Server, e o nome da base que será criada.

Após criar a base vamos adicionar uma Tabela “Pessoa”. Clique com o botão direito na pasta “Table” > “Add New Table”.

image

Crie as colunas com os tipos da imagem abaixo. Na coluna “Codigo”, clique com o botão direito em Set Primary Key, para definir esta coluna como chave primária.

image

Para tornar a coluna código Auto-Incremento, selecione-a e na window de “Column Properties”, defina “Is Identity = Yes”, como na imagem abaixo:

image

Quando for salvar defina o nome “Pessoa”:

image

Vamos inserir algumas linhas nessa tabela, para isso, clique com o botão direito sobre a tabela e selecione “New Query”:

image

Em seguida digite alguns comandos de “insert” e clique no ponto de exclamação em vermelho, como indicado na figura:

image

Após inserir alguns dados, vamos criar uma aplicação de console que irá se conectar na base de dados. Neste primeiro exemplo, iremos listar os dados usando o objeto DataReader, observe:

image

Explicando:

Na linha 16 é definida a variável que representa a string de conexão com o SQL Server, ou seja, qual o caminho para eu conectar na base de dados, com suas devidas configurações e parâmetros de autenticação. Basicamente ela é composta de servidor (podendo ser um IP, assim, poderíamos ter o SQL server em outra máquina que não a de desenvolvimento) com instância do SQL Server, a base de dados inicial e o tipo de autenticação.

Na linha 14 é criado o objeto de conexão com SQL Server passando a string de conexão no construtor. Perceba o uso da palavra reservada “using”. Ela faz o descarte automático do objeto de conexão quando o bloco que ela define for totalmente executado. Isso significa que ela desconecta da base de dados e retira todas as informações desnecessárias da memória, pois abrir e manter uma conexão com uma base de dados é muito custoso. E fica a dica: É possível utilizar o “using” em qualquer objeto que implementa a interface IDisposable, ou seja, todo objeto que pode ser descartado da memória.

Chegou a hora de eu passar o comando SQL criado, para isso utilizamos a classe SqlCommand, passando a string com a instrução SQL, e o objeto de conexão, na linha 18.

Agora que esta tudo pronto para executar o comando, vamos abrir a conexão com o método “Open()”, na linha 20, e resgatar o DataReader (linha 22).

E, enquanto for possível ler linhas que a instrução retornou (linha 24), imprimimos isto na tela, obtendo os dados pelo tipo e índice da coluna (linha 26). Fica registrado que há várias formas de obter a coluna de um DataReader, fique à vontade para explorá-los.

Sendo assim, eis nosso resultado:

image

Agora um exemplo utilizando DataSet:

image

Antes de mais nada a classe DataSet fica no namespace “System.Data”, como na linha 3 indicada na figura acima.

Agora, na linha 19, aparece o DataAdapter recebendo a instrução SQL e a conexão. Ele é que será responsável em recuperar as informações e preencher o DataSet.

Na linha 21 é criado o DataSet, abaixo é aberta a conexão e o DataAdapter preenche o DataSet (linha 24).

Para listar os dados no console, foi feito um “foreach”, obtendo um DataRow (objeto do DataSet que representa uma linha). Percebam que o DataSet tem a capacidade de gerenciar várias tabelas em memória, então, como só temos uma tabela mapeada, pegamos as linhas (Rows) da tabela de índice “0”.

Recuperada a linha, para selecionar a coluna, da linha, é só passar o nome, por string entre colchetes, para o objeto que representa a linha (“item”).

O resultado é o mesmo.

Podemos disponibilizar estes dados facilmente na web. Para tal vamos adicionar uma ASP.NET Web Application na solução:

image

image

Agora, na pagina Default.aspx vamos adicionar um controle que esta apto para receber uma coleção de registros, proveniente da base de dados. Para tal, escolhi a GridView.

image

Basicamente, uma vez que fornecermos uma fonte de dados (coleção de registros) para a GridView, ela irá renderizar uma tabela HTML com as informações. Para forneceremos as informações, vamos para o code behind da página Default.aspx, e no evento Page_Load podemos conectar no banco de dados, resgatar os registros com um select, e de alguma forma fornecer esta coleção para a GridView.

Com o DataSet é mais fácil, apenas atribuímos ele na propriedade DataSouce da GridView, e realizar um DataBind(), método responsável por renderizar a informação vinculada.

Alguns detalhes importantes, para acessar o code behind, abra o arquivo Default.aspx.cs:

image

Temos de tornar esta aplicação a principal, pois o console não nos interessa mais, para isso clique com o botão direito no projeto web > “Set as StartUp Project”:

image

Após estes detalhes, resta a codificação. Vejamos o exemplo da codificação e seu resultado:

image

image

Podemos trabalhar também com o DataReader, porém temos de criar uma lista de objetos. O papel da lista será armazenar os registros em memória e atribuí-la no DataSource da GridView.

Vamos adicionar uma classe “Pessoa” que modelará os objetos da lista,

image

image

image

Agora entramos em um conceito interessante: A interação de um sistema, baseado em linguagem Orientada a Objetos, com uma base de dados relacional.

Já temos nossa classe, resta criar uma lista e os objetos para cada linha recuperada do banco de dados, e adicioná-los em uma Lista tipada (List<>). Vejamos:

image

Visualmente, o resultado é o mesmo, mas lembrando que performaticamente o DataReader é mais ágil.

Não foi muito diferente do exemplo no console, a diferença é que não utilizamos o Console.WriteLine().

Para concluir, vamos voltar na aplicação console, pois agora é hora de explicar como efetuar um comando na base de dados, ganhando assim o poder de inserir, atualizar e apagar registros da base.

image

Para qualquer que seja o comando que deverá ser executado na base de dados (insert, delete, update), devemos utilizar um objeto SqlCommand e o seu método “ExecuteNonQuery()”, que retornará o número de linhas afetadas pelo comando.

Acompanhe o exemplo abaixo:

image

image

Uma instrução de insert esta definida na linha 17. Perceba que ela não recebe diretamente os valores que serão inseridos no banco de dados, pois ela esta recebendo parâmetros. Estes são importantes para evitarmos problema de SQL Injection (injeção de comandos indesejados na string do comando). Então nas linhas 21 e 22 são adicionados parâmetros ao comando, provenientes da classe SqlParameter, passando, no construtor, o nome do parâmetro (com “@”, uma característica do SQL Server, podendo variar a maneira de passar parâmetro, dependendo do Provedor de Dados), e seu valor. O valor é tratado pelo parâmetro, assim evitando dados truncados (no caso de uma Data e Hora) e injeção indevida de SQL (SQL Injection).

Finalmente, na linha 25 executamos o “ExecuteNonQuery()”, inserindo assim mais um registro no SQL Server.

Lembrando que o “ExecuteNonQuery()” da suporte para os comandos de delete e update também.

Para comprovar, podemos voltar no exemplo web, que está com o select, e executar a aplicação.

image

Percebam que o registro inserido, no exemplo acima, esta na linha de Codigo 4.

Espero que tenham gostado, pois o objetivo aqui, foi dar um overview do ADO.NET, focando na conectividade nativa e primitiva do mesmo.

Para quem quiser se aprofundar no assunto, o ADO.NET suporta uma série de frameworks que ajudam a abstrair a camada de dados, e facilitar a interação com o mundo das linguagens Orientadas a Objeto, como o Entity Framework, LINQ to SQL, NHibernate etc… Inclusive DataSets Tipados.

E fica a dica: pense como disponibilizar registros e conectividade com o banco de dados após explorar este artigo de arquitetura, seja de forma primitiva, ou explorando uma solução/framework mais robusto. Se achar que de primeira está difícil, tente criar funções ou classes com métodos que generalizam e o ajudariam com a base de dado.

E este foi um grande overview sobre a base do ADO.NET… Abraços, até mais Smiley mostrando a língua