Atualmente não podemos negar que deparamos diariamente com diversas formas de armazenamento e manipulação de dados. Isto independe do lugar que estamos ou do que fazemos. Se vamos a um mercado, temos computadores que registram as vendas, máquinas de consulta de preços de produtos, terminais para saques eletrônicos, máquinas de cartão de crédito, entre outros. É comum encontrarmos em diversas áreas da nossa vida a presença de máquinas e aplicativos que, de alguma forma, lidam com dados armazenados, dinamizando e facilitando seu acesso.
É comum encontrar aplicações que interagem com algum tipo de informação ou conjunto de informações. Independente da linguagem que foram desenvolvidas, elas visam garantir aos seus usuários segurança, clareza e objetividade na recuperação e manutenção do seu conteúdo. Mas antes de falarmos dos sistemas que fazem o usuário interagir diretamente com os dados, visualizando-os e manipulando-os de forma coerente e usual, é importante termos conhecimento prévio de que as informações manipuladas por eles, em sua maioria, estão armazenadas em um Sistema Gerenciador de Banco de Dados, ou simplesmente SGBD.
Este SGBD deve garantir que os dados estejam armazenados de forma organizada, permitindo atualizações, inclusões e exclusões e garantindo toda segurança e consistência. Por definição temos que SGDB é “um software (ou conjunto de Softwares) responsável pelo gerenciamento (armazenamento e recuperação) dos dados no banco de dados”.
Um SGBD pode gerenciar um ou mais bancos de dados. Mas como definir um banco de dados? Se nós temos um arquivo contendo a tabela de preços dos produtos de uma indústria, nós temos um banco de dados? Conceitualmente, um banco de dados tem de representar uma coleção de dados organizados de forma coerente e com um significado real. Uma tabela de preços, por si só, não tem um significado real sem que existam outras tabelas que interajam com ela. Se nós temos uma tabela de preços, uma tabela de clientes, uma tabela de pedidos e uma tabela de produtos, já podemos montar um quadro que traduz um processo de atendimento a clientes, venda e controle de estoque, ou seja, uma situação real armazenada num banco de dados.
A forma mais comum de interação entre usuário e banco de dados ocorre através de sistemas específicos, que por sua vez acessam o volume de informações geralmente através da linguagem SQL (Strutured Query Language), padrão entre os SGBD´s. A ferramenta de desenvolvimento utilizada para a implementação desses sistemas é tão importante quanto o SGBD que gerencia as informações a serem acessadas por eles. Iremos analisar três grandes ambientes para desenvolvimento: Delphi, VB .Net e Java.
Por que o Delphi?
O Borland Delphi é uma grande opção para o desenvolvimento de sistemas em que é necessário utilizar servidores de Banco de Dados SQL. Inicialmente, é importante frisar que o Delphi possui um suporte bem amplo aos Servidores SQL encontrados hoje no mercado, através da implementação de diversos drivers e engines. Alguns são da própria Borland, como o DbExpress e a obsoleta BDE. Outros são de terceiros, como o ADO (ActiveX Data Objects) da Microsoft. Um driver geralmente é uma DLL, um conjunto de funções utilizadas para acesso e manipulação de dados em um banco. Um engine é um aplicativo que faz a interface ou tradução das mensagens enviadas pela aplicação para o driver, de forma que seja transparente para a aplicação o tipo de driver que está sendo utilizado para acesso ao banco. Uma das grandes novidades do novo Delphi é o suporte através da dbExpress ao servidor Microsoft SQL Server 2000.
Neste artigo usaremos o DbExpress e o ADO como engines de acesso e o banco de dados será o Northwind do Microsoft SQL Server 2000. O ADO, sendo desenvolvido pela Microsoft, se caracteriza como uma ótima opção para conexão ao MSSQL Server, além de facilitar a distribuição da aplicação, uma vez que é suportado nativamente por diversas versões do sistema operacional Microsoft Windows (Win 98 SE, Win ME/2000 Professional, Win XP Home/Professional). Exemplificaremos o mesmo acesso utilizando o DBExpress. Iremos verificar que as diferenças de programação de um Engine de acesso para outro no Delphi são poucas. O que muda mais é o deploy (distribuição) e a performance.
NOTA: Para obter mais informações sobre o ADO, acesse o Microsoft Universal Data Access no endereço: http://www.microsoft.com/data. Lá é possível baixar a versão mais recente do MDAC (conjunto de componentes que, entre outros recursos, inclui o ADO).
Exemplo em Borland Delphi 7
Primeiro iremos exemplificar a conexão utilizando DbExpress.
Passo 1– Iniciando uma nova aplicação
Clique menu File / New / Application como mostra a Figura 1.
Passo 2 – Configurando a conexão
Adicione ao formulário form1 o componente SQLConnection, localizado na paleta de componentes DbExpress. Em seguida, clique com o botão inverso do mouse no componente e selecione Edit Connection Properties, como mostra a Figura 2.
Será exibida uma caixa de diálogo para configuração das propriedades de conexão com o banco de dados. Vamos utilizar a conexão denominada MSSQLConnection (poderíamos adicionar uma nova conexão clicando no botão “+”, selecionando o driver MSSQL e dando um nome para a mesma) e configurar em Connection Settings os demais parâmetros:
- HostName – Nome ou IP da máquina servidora
- Database - Nome do banco de dados no SQL Server
- User_Name - Nome do usuário
- Password - Senha
Para testar a conexão clique no botão “Test Connection” (último da barra de ferramentas com um ícone de engrenagem). A Figura 3 mostra a janela preenchida.
A conexão é aberta através da propriedade Connected do componente SQLConnection (as propriedades são acessadas através do Object Inspector). Podemos alterar esse valor em tempo de design ou tempo de execução. Altere a propriedade LoginPrompt para false para desabilitar a caixa de diálogo de login do banco. Neste caso, o usuário e senha já estão sendo passados diretamente pelo aplicativo. Observe as alterações na Figura 4.
Passo 3– Acessando os dados
Acessaremos a tabela Employees no banco tomado como exemplo. Para isso, insira um componente TSQLQuery, localizado também na paleta DBExpress.
Devemos conectar o SQLQuery ao objeto SQLConnection. Selecione a propriedade SQLConnection do SQLQuery e aponte para SQLConnection1. Em seguida definimos o código da consulta SQL através da propriedade XXXX. Para executar a consulta em tempo de projeto basta alterar a propriedade Active do componente para true. Vide Figura 5.
Passo 4 – Manipulando os dados e executando a aplicação
Para permitir que o usuário manipule os dados selecionados, utilizaremos um componente DbGrid. Este componente está localizado na paleta Data Controls. Uma vez adicionado ao formulário é necessário que esse componente acesse os dados retornados pelo SQLQuery configurado no passo 3. Para isso, utilizaremos três outros componentes: ClientDataSet, DataSetProvider e DataSource que estão localizados na palheta Data Access. Esses componentes devem ser adicionados ao formulário e configurados da seguinte forma:
- DataSetProvider - A propriedade DataSet aponta para o SQLQuery configurado no passo 3.
- ClientDataSet – A propriedade ProviderName aponto para o objeto DataSetProvider.
- DataSource – A propriedade DataSet aponta para o ClientDataSet configurado no passo anterior.
Por fim, para que os dados sejam exibidos no grid adicionado ao formulário, devemos apontar a propriedade DataSource do grid para o objeto DataSource1, alterando a propriedade Active do ClientDataSet para true. Dessa forma os dados serão exibidos no grid, estando prontos para serem manipulados conforme mostra a Figura 6.
O ClientDataSet e o DataSetProvider fazem parte de uma implementação da Borland denominada DataSnap (antigo MIDAS) que disponibiliza para o desenvolvedor o que chamamos de “DataSet Desconectado”. A partir de um DataSet qualquer, que no exemplo foi o SQLQuery, o DataSetProvider monta um conjunto de dados e envia para o ClientDataSet. Feito isso, o SQLQuery, que é o DataSet de origem, não é mais utilizado, bem como a conexão com o banco, e os dados podem ser manipulados sem sobrecarga da rede e consequente degradação da performance da aplicação. Após o término da manipulação dos dados, é necessário a execução do método ApplyUpdates do ClientDataSet, para que sejam aplicados no banco. No exemplo, o evento “OnClick” do botão “Aplica Alterações” deve ser implementado com o seguinte código:
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
ClientDataSet1.ApplyUpdates(0);
end;
O parâmetro do método indica o número de erros que serão desconsiderados antes de ser gerada uma exceção na aplicação. Neste caso o parâmetro indica que não podem ocorrer erros no processamento.
Para cancelar as alterações efetuadas é necessário a execução do método CancelUpdates. Neste caso, o evento “OnClick” do botão “Cancela Alterações” deve ser implementado com o seguinte código:
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
ClientDataSet1.CancelUpdates;
end;
Outra grande vantagem do ClientDataSet e do DataSetProvider é a facilidade que eles disponibilizam para que, se for necessário, seja efetuada uma troca do engine de acesso ao banco. O mesmo programa feito com DBExpress será utilizado para exemplificar o acesso a dados utilizando ADO.
ACESSO AO SQL SERVER COM ADO
Passo 1 – Trocando o componente de conexão com o banco de dados
Em primeiro lugar os componentes SQLConnection e SQLQuery devem ser excluídos do formulário para que possamos adicionar os componentes AdoConnection e AdoQuery localizados na paleta ADO.
No ADO o componente responsável pela conexão é o AdoConnection. Após adicioná-lo no formulário devemos configurá-lo através do acesso ao menu Edit ConnectionString, conforme mostra a Figura 7.
A tela exibida por esta opção permite que utilizemos um Data Link File ou uma Connection String (Figura 8). Utilizaremos esta última de forma a mostrar todo o processo de configuração da conexão. A vantagem de usar Data Link File é que os parâmetros ficam armazenados em um arquivo externo, possibilitando alterações sem a necessidade de “recompilação” do aplicativo.
Para montar a Connection String acessaremos o assistente através do botão build da caixa de diálogo exibida (Figura 8).
Em primeiro lugar devemos configurar o Provider que irá gerenciar a conexão com o banco de dados. Escolheremos o “Microsoft OLE DB Provider for SQL Server” (Figura 9). Após esta seleção devemos informar na pasta Connection os parâmetros para que a conexão seja efetuada. Indique o nome do servidor de banco de dados em “1. Select or enter a server name”, os dados para login em “2. Enter the information to log on to the server” e o banco de dados a ser acessado em “3. Select the database on the serever”. É importante que a opção “Allow saving password” esteja marcada para evitar erros na conexão uma vez que os parâmetros de login (usuário e senha) já estão definidos. Encerradas as configurações podemos testar a conexão através do botão “Test Connection” e em seguida encerrar o assistente através do botão ok (vide Figura 10).
Passo 2 – Adicionando o componente para acesso aos dados
No ADO o componente a ser utilizado para substituir o SQLQuery é o ADOQuery que está na paleta ADO. Uma vez adicionado ao formulário, altere a propriedade Connection apontando-a para o objeto AdoConnection1. Altere a propriedade SQL de forma análoga ao passo 3 do exemplo com DbExpress.
Feito isso, basta alterar a propriedade DataSet do DataSetProvider apontando para o ADOQuery configurado anteriormente. Altere a propriedade Active do ClientDataSet para true e pronto! (Vide Figura 11).
Por que o VisualBasic.Net?
O Visual Basic agora faz parte de um novo conjunto de ferramentas para desenvolvimento de aplicações: a estratégia .Net. O .Net é uma nova plataforma da Microsoft, multi-linguagem, totalmente formulada para lidar com XML e Web Services e voltada para aplicações multi-dispositivos. Nesta plataforma, o ADO também ganhou uma nova implementação chamada ADO.Net e é este engine que iremos focalizar.
O novo ADO.Net foi desenvolvido para ser uma versão bem diferente das anteriores, focando a completa compreensão do XML, o uso de DataSets desconectados e uma implementação mais leve para a Web.
Exemplo em Microsoft VisualStudio.Net (utilizando VB.Net)
Inicie o VisualStudio.Net e clique no menu File|New|Project. Na caixa de diálogo, clique em Visual Basic Projects e escolha Windows Applications na caixa Templates. Digite o nome do projeto e clique em OK, como mostra a Figura 12.
Após estes passos o VisualStudio.Net irá preparar o ambiente para o desenvolvimento de um projeto Visual Basic.
No ADO.Net, assim como nas versões anteriores do ADO, existe o objeto Connection que permite a conexão com o Banco de Dados. Esse objeto, atualmente, não é um objeto único para qualquer tipo de conexão como antes. Agora ele é implementado em diversas classes que utilizam a interface IdbConnection em comum. Usaremos o SQLConnection, um componente Connection implementado para se conectar ao MSSQL Server versão 7x e superiores, para acessar o banco Northwind que acompanha o MSSQL Server 2000.
Na ToolBox no lado esquerdo da aplicação clique na guia “Data” e insira no formulário um componente SQLConnection. Na caixa Properties clique na propriedade ConnectionString e selecione “New Connection...” (Figura 4). Será exibida a janela padrão de configuração de ConnectionString do ADO. O exemplo no Delphi 7 utiliza a mesma janela e explica como configurar a ConnectionString para acessar o banco Northwind em detalhes.
Configurado o componente de conexão é necessário informar de onde serão requisitados os dados. Esta requisição é feita por um objeto Command. Porém, assim como o objeto Connection, o Command possui diversas versões que variam de Provider para Provider. Por exemplo, para acessar o SQL Server, o ADO.Net possui um Provider específico que, para ser utilizado, precisa de um SQLConnection pertencente ao namespace System.Data.SqlClient (implementação que aproveita recursos específicos do MS-SQL) e para se executar uma consulta no Banco deve-se utilizar um objeto SQLCommand, ou mesmo um SQLDataAdapter, também do mesmo namespace (ou seja, também especifico para o MS-SQL). O que implica que é necessário importar este namespace com o comando “Imports”.
Na guia Data da ToolBox clique no componente SQLDataAdapter e insira-o no formulário. Automaticamente o Visual Studio irá apresentar o “Data Adapter Configuration Wizard”, que permite configurar de forma simples o SQLDataAdapter. Este componente tem como função facilitar o gerenciamento das requisições com o Servidor em relação ao DataSet (conjunto de registros), armazenando consultas SQL através das propriedades: DeleteCommand, InsertCommand, SelectCommand e UpdateCommand que permitem ao desenvolvedor especificar comandos SQL para controlar de forma otimizada e padronizada pelo ADO.Net os conjuntos de registros armazenados no Servidor.
Utilizando o Wizard é possível configurar uma consulta simples e entender como se utiliza o SQLDataAdapter no VisualStudio.Net. Na primeira tela clique no botão “Next”, onde será exibido o passo: “Choose Your Data Connection”. Esta tela permite configurar que conexão irá requisitar os dados. Na caixa Combo pode-se especificar a conexão que já foi criada pelo componente SQLConnection inserido anteriormente. Após clique no botão “Next”. Em “Choose a Query Type” especificamos como os dados serão requisitados. Abaixo, segue uma pequena descrição de cada opção:
- Use SQL statements: Permite especificar uma Query SQL que faça o retorno dos dados. O próprio Wizard irá gerar os comandos Delete, Update e Insert baseados nesta Query.
- Create New Stored Procedures: Permite criar novos procedimentos armazenados a partir de uma Query SQL para os comandos Insert, Update e Delete.
- Use Existing Stored Procedures: Permite especificar quais serão os procedimentos armazenados que farão os comandos: Select, Insert, Update e Delete do conjunto de registros específicos para cada situação.
Será utilizada a opção “Use SQL statements” e a configuração da Query com o comando SQL abaixo:
SELECT orderid, customerid, orderdate, shippeddate, shipname, shipregion, shipcountry
FROM Orders
Conforme visto no exemplo acima, será requisitado ao banco de dados apenas alguns campos da tabela de pedidos. Este comando SELECT será inserido na propriedade SelectCommand do SQLDataAdapter.
Clique em “Next”. Serão gerados no Wizard os comandos SQL de acordo com o SELECT para configurar o componente automaticamente. Para finalizar, clique no botão “Finish”.
Pronto! Foi criado um componente SQLDataAdapter que permite fazer consultas e, ainda dentro do padrão ADO.Net, modificar os dados selecionado, através da SQL gerada pelo Wizard.
Os controles Data-Aware do .Net para exibir dados necessitam que estes sejam recebidos de um DataSet. Para gerar um DataSet, clique com o botão direito na figura do SQLDataAdapter no Form Designer e selecione “Generate DataSet”. Será visualizada uma caixa de diálogo onde, pressionando-se o botão “OK”, irá aparecer o componente DataSet.
Em seguida insira um controle DataGrid. Linke a propriedade DataSource ao DataSet recém-gerado e DataMember a tabela Orders, visualizando os dados no grid da mesma forma que no Delphi, como mostra a Figura 13.
Por que o Java?
O Java tem demonstrado seu poder com relação ao mundo multiplataforma. Cada vez mais conhecido no Brasil, muito se tem produzido com Java. Um ponto forte do Java é o fato de grandes empresas estarem investindo nele, como as gigantes Oracle e IBM. Uma das formas de conexão de uma aplicação Java com um banco de dados é através da API JDBC.
O JDBC, Java Database Connectivity, é uma API Java para conexão com SGDB´s diversos e execução de expressões SQL. Sendo mais específico, JDBC é um conjunto de classes e interfaces que permitem acesso a bases de dados relacionais de maneira uniforme, numa solução similar ao ODBC. Existem inúmeras implementações de drivers de bancos de dados compatíveis com JDBC que se enquadram em quatro categorias de soluções, definidas pela JavaSoft:
- Tipo 1 – Ponte JDBC / ODBC
A ponte JDBC / ODBC foi desenvolvida em conjunto pela JavaSoft e a Intersolv, de modo a aproveitar a grande quantidade de drivers ODBC que já existem instalados nas máquinas. Aplicação Java faz uma chamada ao JDBC que por sua vez faz essa chamada ao ODBC e este à API de acesso nativa do banco. - Tipo 2 – Driver Java Parcial + API Nativa
Nesta solução o driver ODBC é eliminado e o driver JDBC converte as chamadas JDBC em chamadas diretas à API nativa do banco. Assim como os drivers do Tipo 1 é necessária a instalação de “aplicações cliente” do banco de dados na máquina onde está sendo executado o aplicativo. - Tipo 3 – Driver 100% Java + Protocolo de Rede (arquitetura em 3 camadas)
Nesta configuração o driver JDBC converte as chamadas JDBC em um protocolo de rede independente (independente do banco de dados). Estas chamadas são convertidas, então, em chamadas à API nativa do banco por um servidor intermediário (middleware). Essa arquitetura na verdade consiste de três camadas. - Tipo 4 – Driver 100% Java:
Nesta solução o driver converte as chamadas JDBC diretamente para o protocolo de rede utilizado pelo banco de dados. Escritos somente em Java, estes drivers não necessitam de ODBC nem de API nativa, gerando um enorme ganho de desempenho e permitindo o desenvolvimento de aplicações 100% Java.
Exemplo em Java
Utilizaremos para acessar o mesmo banco de dados dos exemplos em Delphi e VB .Net (NorthWind do SQL Server) um Driver JDBC do tipo 4 denominado Microsoft SQL Server 2000 JDBC Driver, que pode ser baixado no em http://msdn.microsoft.com/downloads/default.asp?URL=/downloads/sample.asp?url=/MSDN-FILES/027/001/779/msdncompositedoc.xml.
Para exemplificar a conexão em Java, utilizaremos um “console application” onde será mostrado além da conexão a execução de um comando SELECT e o display dos dados retornados na tela. As classes utilizadas e os procedimentos serão explicados em seguida. Vale a pena ressaltar que este exemplo mostra uma das formas de acesso e manipulação de dados em Java.
import java.sql.*;
public class Principal {
public static void main (String[] args) {
Connection conn = null;
try {
DriverManager.registerDriver (
new com.microsoft.jdbc.sqlserver.SQLServerDriver());
conn=DriverManager.getConnection
("jdbc:microsoft:sqlserver:" +
"//servidor:1433;DatabaseName=NorthWind;Selectmethod=cursor",
"usuario",
"senha");
}
catch (SQLException e) {
System.out.println ('\n' + "Erro na conexão com o banco.");
e.printStackTrace();
System.exit(1);
}
try {
PreparedStatement pstmt =
conn.prepareStatement("SELECT * FROM EMPLOYESS");
ResultSet rs = pstmt.executeQuery();
while ( rs.next() ) {
System.out.println(rs.getInt("EmployeeID") + " - " +
rs.getString("LastName") + "," +
rs.getString("FirstName"));
}
pstmt.close();
conn.close();
}
catch (SQLException e) {
System.out.println ('\n' + "Erro ao recuperar dados no banco.");
e.printStackTrace();
System.exit(1);
}
}
}
Inicialmente é declarado um objeto que irá representar a conexão com o banco de dados, neste exemplo chamado de conn, do tipo Connection. Voltaremos a falar nele adiante. Em seguida é executada a seguinte chamada:
DriverManager.registerDriver(
new com.microsoft.jdbc.sqlserver.SQLServerDriver());
O DriverManager é uma classe que gerencia os drivers registrados no JDBC. Este registro é feito através da chamada ao método estático registerDriver. A partir desse momento, a instância do driver passado como parâmetro passa a ser mantida pelo DriverManager e o driver fica disponível para utilização pela aplicação Java.
A próxima linha abre uma conexão com o banco de dados, que é atribuída para o objeto conn para ser manipulada pela aplicação:
conn=DriverManager.getConnection
("jdbc:microsoft:sqlserver:" +
"//servidor:1433;DatabaseName=NorthWind;Selectmethod=cursor",
"usuario",
"senha");
O método estático getConnection tem como parâmetro um String de Conexão, um String que representa o nome do usuário e um último que representa a senha do mesmo. O DriverManager verifica se o driver passado na primeira parte de String de Conexão está registrado no JDBC (como descrito anteriormente). Caso o driver esteja registrado é solicitada a conexão de acordo com os parâmetros passados na segunda parte do String de Conexão (onde temos o nome do servidor, a porta do listner, o nome do banco a ser acessado e o tipo de seleção) além do usuário e senha. Caso a conexão seja efetuada com sucesso, o objeto conn passa a “apontar” para a mesma.
As linhas que seguem enviam o comando SQL para o Servidor de Banco de dados para que o mesmo seja compilado no servidor e fique pronto para execução. Este procedimento é executado através do método prepareStatement do objeto conn (instanciado pelo método getConnection visto anteriormente). Este método, se executado com sucesso, retorna um PreparedStatement que é a instância do comando “preparado” no Servidor e, no nosso exemplo, é manipulado pelo objeto pstmt.
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM EMPLOYESS");
Para acessarmos os dados do comando SQL preparado anteriormente é preciso que tenhamos um objeto do tipo ResultSet que é instanciado a partir do método ExecuteQuery() do PreparedStatement, como mostrado a seguir.
ResultSet rs = pstmt.executeQuery();
Os procedimentos seguintes executam um “loop” nos dados resultantes do comando SQL contidos no ResultSet rs listando na tela os valores das colunas EmployeeID, LastName e FirstName.
while ( rs.next() ) {
System.out.println(rs.getInt("EmployeeID") + " - " +
rs.getString("LastName") + "," +
rs.getString("FirstName") );
}
Por fim, fechamos o PreparedStatement pstmt e o Connection Conn liberando com isso recursos do banco de dados e finalizando a aplicação se forma adequada.
É interessante notar que todos os procedimentos referentes a conexão, a execução de comandos e manipulação de dados estão contidas num bloco protegido (try...catch) pois todos os métodos utilizados propagam SQLException, que representa uma exceção referente ao acesso ou manipulação de um banco de dados, devendo ser tratada pela aplicação.
Conclusão
Nosso objetivo foi mostrar os procedimentos a serem efetuados em cada uma das ferramentas analisadas para conexão e manipulação de dados de um banco no SQL Server, deixando alguns conceitos de forma a facilitar ao analista a definição sobre qual ferramenta usar para cada solução a ser implementada.
De fato, não será somente a escolha da ferramenta de desenvolvimento que irá definir a melhor forma de implementar um projeto com sucesso. O analista que tiver um domínio completo do problema proposto pelo cliente (além de conhecimento e experiência em cada ferramenta) terá mais facilidade de escolher qual tecnologia se tornará mais eficiente para resolver o problema em questão.