i LUCAS ROBERTO BECHERT SCHMITZ Construção de um gerador gráfico de consultas SQL via Web utilizando a plataforma .NET Palmas 2004 ii LUCAS ROBERTO BECHERT SCHMITZ Construção de um gerador gráfico de consultas SQL via Web utilizando a plataforma .NET “Relatório apresentado como requisito parcial da disciplina de Prática de Sistemas de Informação I (Estágio) do curso de Sistemas de Informação, orientado pelo Prof. Jackson Gomes de Souza” Palmas 2004 iii LUCAS ROBETO BECHERT SCHMITZ Construção de um gerador gráfico de consultas SQL via Web utilizando a plataforma .NET “Relatório apresentado como requisito parcial da disciplina de Prática de Sistemas de Informação I (Estágio) do curso de Sistemas de Informação, orientado pelo Prof. Jackson Gomes de Souza” Aprovado em julho de 2004 BANCA EXAMINADORA _____________________________________________ Prof. Jackson Gomes de Souza Centro Universitário Luterano de Palmas _____________________________________________ Prof. Fernando Luiz de Oliveira Centro Universitário Luterano de Palmas _____________________________________________ Profª. Parcilene Fernandes de Brito Centro Universitário Luterano de Palmas Palmas 2004 iv “De que valem leis, onde falta nos homens o sentimento da justiça?” (Obras Completas de Rui Barbosa, v. 16, t. 5, 1889. p. 225.) v AGRADECIMENTOS Agradeço, primeiramente a Deus, tanto por sua bondade em conceder a mim e a todas demais pessoas com quem convivo, uma grande dádiva; quanto por me motivar a ser o que fui, que sou e que pretendo ser a partir desse momento por meio de meus esforços. Agradeço à minha família, que mesmo não podendo estar juntos a mim em todos os momentos nos últimos anos, sempre me deram força para acreditar em meus sonhos e condições para continuar essa caminhada. Agradeço ao meu orientador, o professor Jackson, que sabiamente me orientou no decorer deste trabalho, indicando sempre o melhor caminho para encontrar as respostas necessárias, isso quando já não as respondia. Agradeço aos professores que, através de suas aulas e de atendimentos extraclasse, me passaram parte de seu conhecimento: Ademildo, Aline, Andrés, Augusto, Cristina, Deise, Eduardo Leal, Eduardo Piveta, Fabiano, Fernando, Flávio, Jackson (olha ele de novo), João Nunes, Madianita, Madson, Mário Sérgio, Parcilene, Ricardo e Thereza. Agradeço aos grandes amigos que conheci nesta instituição: André (Rincon), Carlos Eduardo (Careli), Edeilson (Ed), Jorge (Trial), Leandro (Macieira). Agradeço também aos demais amigos, colegas de sala de alua e demais conhecidos; não citarei nomes para não correr o risco de cometer injustiças ao esquecer de alguém. Agradeço também ao leitor que neste momento me prestigia ao ler este trabalho. A ordem dos nomes citados acima não indica preferência, afinal, isto nem mesmo eu sei responder. Os nomes contidos nos parágrafos estão em ordem alfabética. vi SUMÁRIO LISTA DE FIGURAS .............................................................................................VIII LISTA DE TABELAS................................................................................................IX LISTA DE ABREVIATURAS.................................................................................... X 1 INTRODUÇÃO.................................................................................................. 14 2 REVISÃO DE LITERATURA .......................................................................... 16 2.1 JAVASCRIPT E DHTML.................................................................................... 16 2.1.1 JavaScript............................................................................................. 16 2.1.1.1 DynAPI................................................................................................ 18 2.1.1.2 Modelo de objetos do browser............................................................. 20 2.1.2 DHTML ................................................................................................ 21 2.2 ASP.NET ......................................................................................................... 22 2.2.1 ADO.NET ............................................................................................. 29 2.2.1.1 .NET Framework Data Provider.......................................................... 30 2.2.1.1.1 Connection..................................................................................... 31 2.2.1.1.2 Command....................................................................................... 32 2.2.1.1.3 DataReader .................................................................................... 33 2.2.1.1.4 DataAdapter................................................................................... 33 2.2.1.2 DataSet................................................................................................. 34 2.3 BANCOS DE DADOS RELACIONAIS .................................................................... 35 2.3.1 Linguagem de Consulta ao Banco – SQL .............................................. 36 3 MATERIAL E MÉTODOS ............................................................................... 40 3.1 3.2 3.3 4 LOCAL E PERÍODO ............................................................................................ 40 MATERIAL ........................................................................................................ 40 METODOLOGIA ................................................................................................. 41 RESULTADOS E DISCUSSÃO ........................................................................ 44 4.1 4.2 4.3 4.4 4.5 MODELAGEM DO SISTEMA ................................................................................ 44 INTERPRETAÇÃO DO ESQUEMA RELACIONAL DO MICROSOFT SQL SERVER...... 47 INTERFACE GRÁFICA ......................................................................................... 50 GERAÇÃO DA CONSULTA SQL.......................................................................... 52 COMUNICAÇÃO COM O BANCO DE DADOS E EXIBIÇÃO DE REGISTROS ............. 53 5 CONSIDERAÇÕES FINAIS ............................................................................. 56 6 TRABALHOS FUTUROS ................................................................................. 58 REFERÊNCIAS BIBLIOGRÁFICAS ...................................................................... 60 APÊNDICE A - CÓDIGO REFERENTE À CLASSE BANCO .............................. 62 APÊNDICE B - CÓDIGO REFERENTE À CLASSE VALIDA ............................. 65 APÊNDICE C - CÓDIGO REFERENTE À CLASSE CONSULTA....................... 66 vii APÊNDICE D - CÓDIGO REFERENTE À CLASSE TABELA ............................ 70 viii LISTA DE FIGURAS Figura 1: Visão simplificada da arquitetura do sistema............................................ 15 Figura 2: Exemplo de código em JavaScript............................................................. 17 Figura 3: Exemplo de código para a utilização da DynAPI ...................................... 19 Figura 4: Código com a utilização da DynAPI para a crição de uma nova Layer..... 19 Figura 5: OZEMAIL (2004) Hierarquia de objetos do Browser. ............................... 21 Figura 6: Modelo compilação ASP. Fonte AÉCE (2004). ......................................... 26 Figura 7: Modelo compilação ASP.NET. Fonte AÉCE (2004). ................................. 26 Figura 8: Preenchendo um menu de seleção HTML com ASP tradicional................. 27 Figura 9: Preenchendo um DropDownList com ASP.NET. ....................................... 27 Figura 10: MSDN (2004) Arquitetura do ADO.NET. .............................................. 30 Figura 11: Formas de acesso a fontes de dados...................................................... 31 Figura 12: Exemplo de utilização do SqlConnection............................................... 32 Figura 13: Exemplo de utilização do objeto SqlCommand. ..................................... 32 Figura 14: Exemplo de utilização do objeto SqlDataReader............................. 33 Figura 15: Exemplo de utilização do objeto SqlDataAdapter. ......................... 33 Figura 16: Exemplo de utilização do objeto DataSet........................................... 34 Figura 17: Representação da tabela tbProduto em uma base de dados relacional.. 35 Figura 18: Consulta básica utilizando a linguagem SQL ........................................ 37 Figura 19: Tabela retornada como resultado da consulta apresentada na Figura anterior (18). 37 Figura 20: Consulta com a cláusula WHERE. ........................................................ 38 Figura 21: Consulta com o operador de comparação BETWEEN na cláusula WHERE. 38 Figura 22: Exemplo de consulta SQL com a cláusula de ordenação ORDER BY .... 39 Figura 23: Modelo de Classes do Sistema desenvolvido nesse trabalho. ................. 45 Figura 24: Implementação do método retornarTabelas() da classe Banco. 50 Figura 25: Interface gráfica do sistema. ................................................................. 51 Figura 26: Código responsável por montar a cláusula FROM a partir da interface gráfica 53 Figura 27: Trecho de código responsável por apresentar ao usuário o resultado da consulta. 54 ix LISTA DE TABELAS Tabela 1: Relação entre Web Controls e elementos HTML ....................................... 25 Tabela 2: Cronograma de atividades para o desenvolvimento do trabalho. .............. 41 x LISTA DE ABREVIATURAS ASP = Active Server Pages ASP.NET = Active Server Pages .NET API = Application Program Interface BOM = Browser Object Model CLR = Common Language Runtime CSS = Cascading Style Sheets DHTML = Dynamic HTML HTML = Hyper Text Markup Language IIS = Internet Information Services MSIL = MicroSoft Intermediate Language SQL = Structured Query Language W3C = World Wide Web Consortium xi RESUMO Este trabalho propõe a implementação de um utilitário Web semelhante ao criador gráfico de consultas já existente em alguns gerenciadores de bancos de dados para desktop. Com este gerador gráfico de consultas, o usuário poderá, entre outras funcionalidades, visualizar uma lista de tabelas existentes no banco de dados, visualizar uma lista de campos de cada tabela e selecionar os campos de uma tabela para que os mesmos possam ser exibidos na consulta. A utilização do utilitário desenvolvido neste trabalho será de grande importância no sentido de facilitar ao usuário o acesso às informações, uma vez que através do sistema o próprio usuário irá montar suas consultas. Palavras-chaves: DHTML, SQL, plataforma .NET xii ABSTRACT This work purposes the implementation of a web utility seem to the graphic query creator that already exists in some desktop database managers. With this graphic query generator, the user can, among other functionality, to visualize a list of tables that exists in the database, to visualize a list of columns of each table and to select the columns from a table for the exhibition of them on the query. The use of the utility developed in this work will be of great importance for making easy to the user the access to the information, because through the system that user will construct his own queries. Keywords: DHTML, SQL, .NET plataform 13 1 INTRODUÇÃO Os sistemas voltados para a Web vêm ganhando cada vez mais espaço. Estes sistemas tornam-se complexos, possuindo funcionalidades de acesso a bancos de dados e gerenciamento de transações. Geralmente, quando um usuário do sistema deseja visualizar informações do banco de dados, acessa as funcionalidades de relatórios já implementadas no sistema; quando algum relatório com informações das quais ele necessita não existe disponível no sistema, o usuário pode tentar entrar em contato com a equipe de desenvolvimento e solicitar que essa nova funcionalidade seja implementada. Esta situação pode gerar dificuldades tanto para o desenvolvedor, que precisará implementar a funcionalidade, quanto para o usuário, que muitas vezes não dispõe de tempo para esperar que a funcionalidade solicitada seja fornecida. Este trabalho propõe a implementação de um utilitário semelhante ao criador gráfico de consultas já existente em alguns gerenciadores de bancos de dados para desktop, tais como o SQL Server Enterprise Manager e o Microsoft Access. Com este gerador gráfico de consultas, o usuário poderá, entre outras funcionalidades: visualizar uma lista de tabelas existentes no banco de dados, visualizar uma lista de campos de cada tabela e selecionar os campos de uma tabela. O diferencial deste trabalho é que o gerador de consultas será acessível via Web. O modelo gráfico da consulta é uma representação visual das tabelas que estão selecionadas para a consulta e dos campos que serão exibidos. Ainda, os relacionamentos entre as tabelas também são representados (na forma de ligações entre as tabelas). O sistema criará a representação em linguagem SQL a partir do modelo gráfico criado pelo usuário. À medida que o modelo gráfico é modificado, a consulta também é modificada, para ficar de acordo com as modificações realizadas na estrutura do modelo gráfico. Caso o usuário que esteja utilizando o sistema tenha um conhecimento maior sobre a linguagem SQL, ele pode alterar a consulta diretamente. Uma representação da arquitetura do sistema pode ser vista na Figura 1. 14 Figura 1: Visão simplificada da arquitetura do sistema. Como visto na Figura 1, o sistema funcionaria da seguinte maneira: a aplicação faz um acesso a uma base de dados para fornecer ao usuário a lista das tabelas disponíveis e dos seus respectivos campos. Após conhecer a estrutura da base de dados o usuário monta a consulta desejada tanto através da parte gráfica (DHTML), como na linguagem SQL através de um editor de texto simples. Ao terminar de definir a consulta e executá-la, o sistema faz um novo acesso à base de dados, agora para buscar o resultado da consulta gerada pelo usuário. Por fim é retornado o resultado da consulta em forma de uma tabela com os campos e seus respectivos valores em cada um dos registros retornados. O texto deste trabalho está organizado da seguinte forma: na seção 2 é apresentada a revisão de literatura, que traz as informações necessárias para se entender as tecnologias utilizadas no desenvolvimento deste trabalho. A seção 3 traz uma descrição dos mateiais e métodos que foram seguidos e utilizados para a realização do trabalho. Na seção 4, são demonstrados os resultados obtidos através da finalização do trabalho e algumas propostas de trabalhos futuros. Por fim, na seção 5 são descritas as considerações finais e na 6 são descritas as referências utilizadas durante o desenvolvimento do trabalho. 15 2 REVISÃO DE LITERATURA Como parte integrante deste trabalho, foi realizada uma revisão bibliográfica sobre os recursos a serem utilizados no decorrer do desenvolvimento do mesmo. Entre estes estão os disponibilizados na plataforma .NET, como os recursos de programação Web e de acesso a banco de dados. Outro recurso utilizado foi a DynAPI, uma biblioteca de classes Cross-Browser para códigos JavaScript. Estes e os demais itens utilizados serão vistos com mais detalhes através das próximas seções. 2.1 JavaScript e DHTML Nesta seção serão esplanadas as tecnologias utilizadas para a criação da interface gráfica da geração da consulta SQL por parte do usuário. Entre essas tecnologias estão o JavaScript e a DHTML. 2.1.1 JavaScript FEATHER (1997) afirma que em um esforço da Netscape para expandir as funcionalidades de seu browser, esta desenvolveu uma linguagem de programação que pode ser embutida em páginas Web. Inicialmente essa linguagem foi chamada de LiveScript, mas logo foi rebatizada para JavaScript, aproveitando a popularidade da linguagem de programação Java da Sun Microsystems. JavaScript possui uma sintaxe muito próxima a Pascal, C e C++. Para FEATHER (1997) JavaScript é uma linguagem dirigida por eventos e estes são definidos pelas ações que podem ocorrer em uma página Web, como por exemplo, um 16 botão ser clicado, o mouse ser arrastado ou o botão do mouse ser clicado. Sendo assim, sempre que algum evento ocorre na página, um código JavaScript pode ser acionado. JavaScript é uma linguagem de script utilizada para tornar as páginas mais interativas com o usuário. Algumas características de JavaScript são definidas por W3SCHOOLS-JS (2004): • Projetado para adicionar interatividade a páginas HTML • É uma linguagem de programação leve; • É usualmente embutida no código HTML; • É uma linguagem interpretada; • Suportada pela maiora dos browsers; • Pode alterar o código HTML dinamicamente; • Orientada a eventos; Um exemplode código JavaScript é demonstrado na Figura 2. 1: 2: 3: <HTML> ... <script language = "JavaScript"> 4: 5: 6: 7: 8: 9: 10: 11: 12: function colorir(obj) { obj.style.backgroundColor = "green"; obj.style.fontColor = "black"; } </script> ... <BODY> <input type = "button" id = "teste" value = "colorir" onClick = "javascript:colorir(this)"> 13: </BODY> 14: </HTML> Figura 2: Exemplo de código em JavaScript. A Figura 2 traz um exemplo da utilização do JavaScript. Como pode ser visto, a linha 3 demonstra o início de um código JavaScript, através da tag <script> e da definição do atributo language como sendo igual a JavaScript. As linhas de 4 a 8 trazem o código que define uma função denominada colorir, que altera algumas propriedades do objeto obj, passado como parâmetro. A linha 9 traz a finalização do 17 código JavaScript através da tag </script>. A função colorir foi chamada apartir da ocorrência do evento onClick definido na linha 12. O objeto obj que tem suas propriedades alteradas é o próprio botão, já que como pode ser observado também na linha 12, quando se define o evento onClick para o botão, é chamada a função JavaScript colorir e a ela é passado o parâmetro this, que em JavaScript significa o próprio objeto, ou seja, o botão que chama a função. Para atender a um dos requisitos do trabalho, o de possuir um código CrossBrowser, ou seja, funcionar independentemente do Browser que o cliente utiliza, utilizouse uma API para a construção dos códigos JavaScript Cross-Browser, a DynAPI, que será descrita na próxima subseção. 2.1.1.1 DynAPI DYNAPI (2004) define a DynAPI como sendo uma biblioteca JavaScript CrossBrowser usada para criar componentes HTML dinâmicos em uma página Web. Esta biblioteca é de domínio público (código livre) e existem várias versões disponíveis para download no seguinte endereço: <http://sourceforge.net/project/showfiles.php?group_id=5757>. Seus principais objetos são: • DynObject; • DynLayer; • DynDocument; Para utilizá-la devem ser seguidos alguns passos, como se estivesse adicionando arquivos de cabeçalho em um programa feito em uma linguagem de programação convencional (em linguagem C, por exemplo, #include <arquivo.h>). A forma de adicionar a biblioteaca DynAPI em códigos JavaScript é demonstrada na Figura 3, a seguir. 1: 2: 3: 4: 5: 6: 7: 8: <script language="Javascript" src="dynapi/src/dynapi.js"> DynAPI.setLibraryPath('dynapi/src/lib/'); DynAPI.include('dynapi.api.*'); DynAPI.include('dynapi.api.dynlayer.js'); DynAPI.include('dynapi.api.dyndocument.js'); ... </script> ... 18 Figura 3: Exemplo de código para a utilização da DynAPI A Figura 3 demonstra um trecho de código necessário para a utilização de alguns dos objetos e métodos da DynAPI. Na linha 1, tem-se o trecho responsável por adicionar à página o arquivo dynapi.js que é a base para a utilização da DynAPI. A seguir, na linha 2, o caminho de onde serão buscados os demais arquivos da biblioteca é definido, através do método setLibraryPath, que recebe como parâmetro o endereço físico de onde estão os arquivos da biblioteca. Ainda no mesmo script podem ser adicionados outros arquivos da DynAPI, dependendo dos objetos com os quais se deseje trabalhar; como, por exemplo, na linha 4 é adicionada a classe responsável para o trabalho com layers, a dynapi.api.dynlayers.*. As layers são representadas em HTML pelos elementos DIV e SPAN. Suas características serão melhor detalhadas na subseção que trata a DHTML. Um trecho de código utilizando as classes adicionadas ao documento pode ser visualizado na Figura 4. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: ... function criarLayer() { var novaLayer = new DynLayer(); novaLayer.setId(‘id’); novaLayer.setSize(200,100); novaLayer.setHTML(‘<p>NovaLayer</p>’); novaLayer.setBgColor(‘#CCCCCC’); novaLayer.moveTo(300,10); DynAPI.document.addChild(novaLayer); DragEvent.enableDragEvents(novaLayer); DragEvent.setDragBoundary(novaLayer); } ... Figura 4: Código com a utilização da DynAPI para a crição de uma nova Layer. A Figura 4 apresenta um código JavaScript com a utilização da DynAPI para acrescentar uma layer à página dinamicamente, além de fazer modificações em algumas de suas propriedades e possibilitar que a mesma seja movimentada pelo usuário. Essas ações estão representadas nas seguintes linhas do código: • Linha 4: a layer é criada; • Linhas 5 a 9: algumas propriedades são modificadas, na seguinte ordem: o 5: Identificador da layer tem seu valor definido como "id"; 19 o 6: O tamanho a layer é modificado para 200 pixels de largura e 100 pixels de altura; o 7: O texto HTML "<p>Nova Layer</p>" é definido como conteúdo da layer; o 8: A cor de fundo da layer passa a ser #CCCCCC (cinza); o 9: A layer é posiciona na página com as coordenadas (x,y) = (300,10), ou seja, 300 no sentido da esquerda para a direita e 10 no sentido de cima para baixo; • A linha 10 adiciona a layer ao documento HTML. A partir desse momento o usuário passa a visualizá-la em seu browser; As linhas 11 e 12 são responsáveis por tornar a layer movimentável pelo usuário através da classe DragEvent, que trata os eventos de movimentação do mouse de forma que o usuário possa mover a layer para qualquer local na janela do navegador onde se encontra o documento. 2.1.1.2 Modelo de objetos do browser KANTOR (2003) diz que a janela que utilizamos para exibir documentos HTML é interpretada pelo browser como uma coleção de objetos. Essa coleção de objetos é conhecida como BOM (Browser Object Model). A Figura 5 ilustra o modelo hierárquico dos objetos do browser. Esses objetos permitem toda manipuação feita em uma página web. 20 Figura 5: OZEMAIL (2004) Hierarquia de objetos do Browser. Conforme apresentado na Figura 5, o objeto principal dessa hierarquia é o Window. À partir dele temos outros três objetos, conforme apresentam KANTOR (2003) e OZEMAIL (2004): • document: que representa todo o documento HTML a ser exibido; • history: que contém o histórico dos documentos acessados pelo usuário; • location: que mantém informações da localização (URL) do documento atual; O objeto document por sua vez, traz outros objetos como: Anchor, Applet, Area, Form, Image e Link, que são utilizadas de forma a estruturar o documento. Esses objetos, que também são tratados neste trabalho como elementos, possuem características específicas que definem sua forma, coloração, tamanho e posicionamento em um documento HTML. 2.1.2 DHTML DHTML é um conjunto de tecnologias que disponibilizam as ferramentas necessárias para tornar dinâmica a linguagem HTML. Para UPHOSTING (2004) DHTML disponibiliza, entre outras funcionalidades: • Animação: através da movimentação de elementos em uma página; • Formatação e posicionamento: através da flexibilidade para formatar elementos HTML como: alterar a cor, o tamanho, a fonte, o posicionamento e outras características; • Interação: através de uma linguagem de programação do lado do cliente, como o JavaScript, para gerar essa interação com o usuário. DHTML pode ser definido como a capacidade que os browsers têm de adicionar movimento e interatividade aos vários elementos que compõe uma página web. Isto é possível através de uma combinação entre HTML, CSS e Javascript (SILVA, 2001). 21 O principal componente dinâmico a ser utilizado neste trabalho é a layer. Em HTML uma layer é representada pelos elementos LAYER (para o Browser Netscape Navigator) e DIV ou SPAN (para outros Browsers). Para W3C (2004) os elementos DIV e SPAN oferecem um mecanismo genérico para adicionar estrutura aos documentos. W3C (2004) afirma ainda que esses elementos definem conteúdo de forma inline (caso do elemento SPAN) ou blocos de conteúdo (caso do elemento DIV). Entre as principais características desses elementos estão (MSDN, 2004): • Propriedades o id: String identificadora do elemento; o outerHTML: conteúdo HTML do elemento; o clientHeight: altura do elemento; o clientLeft: distância entre o lado esquerdo do elemento e o limite esquerdo do documento ao qual ele pertence; o clientTop: distância entre o topo do elemento e o topo do documento em que ele está contido; o clientWidth: largura do elemento; • Eventos o onclick: disparado quando o usuário clica com o botão do mouse sobre o elemento; o ondragstart: disparado quando o usuário inicia o processo de arrastar o elemento com o mouse; o ondrag: disparado continuamente enquanto o elemento está sendo arrastado; o ondragend: disparado quando o usuário solta o botão do mouse, finalizando assim, o processo de arrasto do elemento. 2.2 ASP.NET W3SCHOOLS-ASP (2004) afirma que um arquivo desenvolvido com a tecnologia ASP pode conter texto, tags HTML e scripts. ASP é uma tecnologia Microsoft e necessita do IIS (Internet Information Services), servidor Web da plataforma Windows, para ser 22 executado. Quando uma página ASP é solicitada, o servidor interpreta o arquivo linha-alinha processando os scripts e retorna ao cliente apenas código HTML. Segundo PAYNE (2001), o ASP.NET é mais que uma atualização do ASP clássico: apresenta um novo modelo de programação e uma grande variedade de ferramentas. MSDN (2004) diz que ASP.NET fornece um modelo unificado de desenvolvimento para a Web que inclui serviços necessários para a construção de aplicações. É parte da plataforma .NET Framework e permite que se faça uso das característcas que esta oferece. MSDN (2004) afirma ainda que a plataforma .NET é um componente Windows completo que apoia a construção e a execução de aplicações. Para D’ANGELO (2003) a plataforma .NET é um ambiente que permite o desenvolvimento de aplicações desktop (Windows ou console), aplicações para aparelhos móveis (palm-tops, celulares, etc.) e o desenvolvimento de aplicações web através da tecnologia ASP.NET. O .NET proporciona um ambiente de desenvolvimento com muitos recursos para os desenvolvedores. Pode-se dizer que o .NET disponibiliza um ambiente de desenvolvimento, que possui, entre outras características (MSDN, 2004): • Multi-plataforma: similar à tecnologia Java: todo o código é compilado, interpretado, depurado e transformado em uma linguagem intermediária. Na plataforma .NET essa linguagem é a MSIL (Microsoft Intermediate Language). A MSIL é entendida apenas pela CLR (Common Language Runtime) da plataforma, diz D’ANGELO (2003). Quando o programa é executado pela primeira vez, a CLR transforma o código MSIL em código de máquina para que este possa ser interpretado pelo processador. Sendo assim, toda aplicação construída na plataforma .NET pode ser executada em qualquer sistema operacional, desde que este por sua vez, tenha uma CLR desenvolvida. Atualmente, existem projetos de implementação do .NET Framework para o sistema operacional Linux. MONO (2004) apresenta que o projeto Mono é um esforço patrocinado pela Novell para o desenvolvimento de uma versão de código aberto do .NET Framework. Essa versão incluirá um compilador para a linguagem C#, uma CLR e um conjunto de classes, assim como na versão da Microsoft; 23 • Multi-dispositivos: segundo D’ANGELO (2003), através da .NET pode-se desenvolver programas web, desktop e também para dispositivos móveis, como telefones celulares e palm-tops; • Multi-linguagem: de acordo com D’ANGELO (2003), o que importa para a plataforma .NET é o código MSIL e a CLR, logo, a mesma não se limita a trabalhar com apenas uma linguagem de programação. Para ser utilizada na plataforma a linguagem de programação deve ser compatível com a CLS (Common Languagem Specification), visto que a CLS é compatível com a plataforma de desenvolvimento .NET e gera códigos MSIL compatíveis com a CLR, diz D’ANGELO (2003). Atualmente existem três linguagens homologadas seguindo a CLS, são elas: C#, J# e VB.NET; • Orientada a objetos: A .NET dá suporte total à programação orientada a objetos, o que significa também que as linguagens homologadas para a plataforma devem prover esse suporte (D’ANGELO, 2003) e (MSDN, 2004); • Interoperabilidade entre linguagens: D’ANGELO (2003) afirma que classes escritas em determinada linguagem, após compilado o código-fonte, quando é gerada a sua correspondente MSIL, pode ser utilizada por programas desenvolvidos em outras linguagens suportadas pela Plataforma; • Uma vasta biblioteca de classes: entre elas estão classes de acesso e manipulação de dados, classes de manipulação de informações transmitidas via Web, classes para trabalhar com objetos visuais, etc (D’ANGELO, 2003). Analisando as informações supracitadas, pode-se dizer que a .NET possui um modelo de desenvolvimento muito parecido com o modelo do Java, onde, na compilação do código-fonte do programa, um novo código, em uma outra linguagem, é gerado para que possa ser entendido em ambientes diferentes. Já que classes desenvolvidas em .NET podem ser acessadas por diversos dispositivos, pode-se tomar como um exemplo a criação de uma classe denominada “Professores”, que conterá métodos e atributos necessários para gerenciar informações 24 referentes aos professores de uma instituição de ensino (por exemplo: cadastrar professores na base de dados, buscar por professores, alterar dados cadastrais, etc.). Essa classe pode ser acessada pelo sistema Web da instituição, pela aplicação desktop da máquina do departamento pessoal e pelo Palm-top do diretor quando estes desejarem, por exemplo, consultar ou cadastrar professores. Para D’ANGELO (2003) a classe acessada por todos será a mesma, diferenciando apenas a forma de disponibilização das informações ao usuário. Essas formas são as extensões específicas para cada tipo de plataforma ou ambiente de desenvolvimento. Para os aplicativos acessados via Web existem APIs denominadas Web Forms e Web Controls, porém aplicativos Web também podem se utilizar das mesmas APIs para desktop. Para as aplicações desktop são utilizadas as extensões denominadas Windows Forms, extensões estas que são APIs utilizadas no desenvolvimento do layout das janelas do aplicativo. MSDN (2004) afirma que Web Controls são componentes visuais que fazem parte de plataforma .NET Framework e auxiliam o desenvolvedor na criação de páginas Web. Esses componentes, em sua grande maioria, são semelhantes aos elementos HTML. A Tabela 1 trás uma relação de alguns Web Controls e os seus corresponedentes em HTML. Web Control Elemento HTML DropDownList <Select> TextBox <Input type="text"> Button <Input type="button"> Table <table> TR <tr> TD <td> Para que os Web Controls possam ser interpretados pelo Browser, antes de o servidor enviar a página ao cliente, a própria plataforma .NET faz uma espécie de tradução do código, convertendo todos Web Controls em seus respectivos elementos HTML. As Figuras 6 e 7 a seguir apresentam a diferença, citada anteriormente, existente entre as formas de compilação do ASP.NET e do ASP tradicional. 25 Figura 6: Modelo compilação ASP. Fonte AÉCE (2004). Figura 7: Modelo compilação ASP.NET. Fonte AÉCE (2004). Conforme pode ser observado analisando as Figuras 6 e 7, existe muita diferença entre os modelos de compilação de um código ASP e de um código ASP.NET. Na tecnologia ASP o código é sempre interpretado antes do envio ao cliente, ou seja, a cada acesso a página é novamente interpretada. Enquanto que, através do modelo de compilação proposto pelo ASP.NET, as páginas primeiramente são compiladas gerando o código MSIL, depois esse código é interpretado pela CLR. Após essas etapas o cliente recebe a página solicitada. A princípio esse processo pode parecer mais demorado que o do ASP, mas vale ressaltar que uma vez feito esse processo, ele só se repete quando o arquivo original sofre alguma alteração. A modificação veio para possibilitar que aplicações desenvolvidas com a .NET Framework pudessem ser executadas em qualquer sistema operacional que dá um suporte à plataforma. Além da forma de compilação, também sofreu uma modificação considerável na forma de se escrever o código. Como exemplos dessa diferença entre o ASP tradicional e o ASP.NET podem ser visualizadas as Figuras 8 e 9 a seguir. 26 1: 2: 3: 4: 5: 6: 7: 8: Dim conn Dim rs Set rs = Server.CreateObject("ADODB.Recordset") conn.Open rs.Open "SELECT * FROM tbAlunos",conn If Not rs.EOF Then Response.Write ("<select name = 'DdlAlunos'>") Response.Write ("<option value = 'idAluno'>Nome do Aluno</option>") 9: While Not rs.EOF 10: Response.Write ("<option value = " & rs("idALuno")) 11: Response.Write (">" & rs("nome") & "</option>") 12: rs.Movenext 13: Wend 14: Response.Write ("</select>") 15: End If 16: rs.Close 17: conn.Close 18: Set rs = Nothing 19: Set conn = Nothing Figura 8: Preenchendo um menu de seleção HTML com ASP tradicional. 1: Dim conn As SqlConnection = New SqlConnection("STRING_DE_CONNECCAO") 2: Dim cmd As SqlCommand = New SqlCommand("SELECT * FROM tbAlunos", conn) 3: DdlAlunos.DataTextField = "Nome do Aluno" 4: DdlAlunos.DataValueField = "idAluno" 5: conn.Open() 6: DdlAlunos.DataSource = cmd.ExecuteReader 7: DdlAlunos.DataBind() 8: Conn.Close() 9: ... 10: <asp:DropDownList id="DdlAlunos" runat="Server"> 11: ... Figura 9: Preenchendo um DropDownList com ASP.NET. Como visto acima nas Figuras 8 e 9, com a plataforma .NET, o modelo de escrita do código sofreu uma grande modificação em comparação ao modelo anterior (ASP). Essa modificação se fez tanto na quantida de de classes disponíveis como na forma de utilização dessas classes. Para melhor entender essas diferenças segue-se uma explicação dos códigos acima. Na Figura 8 tem-se um código em ASP. Nas linhas 1 e 2 são criadas as variáveis que irão ficar responsáveis pela conexão com o banco de dados (conn) e por armazenar as informações consultadas (rs) - na sub-seção ADO.NET (2.2.1), esses termos de conexão com o banco de dados e armazenamento de informações serão melhor explanados. Nas 27 linhas 3 e 4 é feita a conexão com o banco de dados e na linha 5 uma consulta é executada para retornar todos os registros da tabela tbAlunos; na linha 6 há uma verificação para identificar se a consulta retornou algum registro; após essa verificação, na linha 7 é criado um elemento HTML do tipo SELECT (menu de seleção) com o nome DdlAlunos; na linha 8 uma opção é inserida com o valor ' idAluno'e com o rótulo ' Nome do Aluno' ; AS linhas de 9 a 13 fazem um laço de repetição para percorrer os registros retornados pela consulta executada anteriormente. Nesse laço de repetição novas opções são adicionadas ao menu HTML criado. As linhas 16 a 19 são utilizadas para fechar a conexão com o banco limpar o conteúdo das variáveis utilizadas, liberando recursos do servidor. Já na Figura 9, com a utilização da tecnologia ASP.NET e da plataforma .NET, um código com função idêntica ao da Figura 8 se torna mais simples. A explicação dessa simplicidade é que a plataforma .NET traz as vantagens da programação orientada a objeto e alguns objetos de interface gráfica da linguagem HTML. O menu de seleção utilizado no código da Figura 8 é representado em ASP.NET pelo objeto DropDownList. Logo, explicando a Figura 9 temos: Nas linhas 1 e 2 a crição da conexão com o banco de dados (que também possui objetos específicos no ASP.NET e serão vistos na próxima subseção) e a criação da consulta a ser executada no banco de dados; As linhas 3 e 4 adicionam a primeira opção do menu, equivalentes à linha 8 da Figura 8; a linha 5 abre a conexão com o banco de dados; na linha 6 a consulta é executada no banco de dados e na linha 7 o objeto é preenchido com os valores retornados pela consulta; a linha 8 fecha a conexão com o banco de dados e a linha 10 mostra como o objeto é utilizado através do código HTML. Como pode-se perceber, o código em ASP faz uso do método Write do objeto Response para criar conteúdo HTML para o cliente; já o ASP.NET não adota esta metodologia, já que a página e seus objetos (controles) são interpretados, e podem ser modificados através de suas propriedades. Esta é uma grande modificação no conceito de programação para a web trazido pela plataforma .NET: os elementos da página se tornam objetos que podem ser modificados programaticamente. Outro ambiente onde isso acontece de forma mais constante e necessária é na programação para desktop, na qual todos os componentes visuais utilizados possuem suas propriedades expostas através de um modelo de objeto e podem ser modificadas via linguagem de programação. 28 Esta analogia é visível, também, quando se interpreta a definição dos Web Forms: formulários para a web; ou seja, são como formulários de programas Desktop (janelas), acessíveis através do browser, na Internet. Dando continuidade aos estudos da plataforma .NET, a próxima subseção tratará da forma como a aplicação fará o acesso à base de dados, utilizando uma biblioteca de classes contida no .NET Framework: a ADO.NET. 2.2.1 ADO.NET Juntamente com a plataforma .NET, a Microsoft desenvolveu uma biblioteca de classes para acesso a banco de dados denominada ActiveX Data Model .NET (ADO.NET). Algumas das características e funcionalidades dessa biblioteca serão descritas nas próximas subseções. DICKINSON (2002) define ADO.NET como um conjunto de classes disponíveis no .NET Framework para fazer o acesso a dados. A ADO.NET se baseia em acesso conectado e desconectado à fonte de dados. O acesso conectado é aquele que mantém uma conexão com a fonte de dados durante toda a execução da aplicação. Enquanto que o acesso desconectado é aquele em que a aplicaçao se conecta com a fonte de dados apenas para carregar e atualizar dados, diminuindo assim a quantidade de recursos utilizados pelo sistema. Para WATSON (2002) o ADO.NET é formado basicamente por dois componentes fundamentais: o .NET Framework Data Provider e o DataSet, conforme pode ser observado na Figura 10, a seguir. 29 Figura 10:MSDN (2004) Arquitetura do ADO.NET. Conforme pode ser visto na Figura 10 acima, o .NET Framework Data Provider permite a conexão com a fontre de dados e a manipulação desses dados através de comandos SQL; e o DataSet faz um acesso desconectado à fonte de dados. Para um melhor entendimento esses dois componentes serão mais detalhados nas subseções a seguir. 2.2.1.1 .NET Framework Data Provider Formado por um conjunto de provedores de acesso a dados. Até o presente momento exitem quatro principais provedores de acesso: • ODBC • OLE DB • SQL • Oracle Para cada um deles existem namespaces específicas que fornecem objetos para acessar e manipular dados. Como esses objetos de acesso e manipulação de dados existem igualmente para os quatro provedores citados acima, para fazer a utlização destes na aplicação basta acrescentar, como prefixo ao nome do objeto, o provedor que se deseja 30 utilizar. Na Figura 11 são apresentadas as formas de com a aplicação faz o acesso à fonte de dados através de cada um dos provedores. Figura 11: Formas de acesso a fontes de dados. Conforme exibido na Figura 11, pode-se perceber que os objetos ADO.NET SQL e Oracle fazem um acesso direto através de uma API do próprio banco de dados, enquanto que os objetos ADO.NET ODBC e OLE DB passam por uma camada intermediária representada pelos seus respctivos provedores, explica MACDONALD (2002). Sendo assim podemos concluir que em se tratando de objetos SQL ou Oracle, o acesso será mais direto e conseqüentemente mais rápido à fonte de dados, pois não haverá a figura de um mediador na conexão. Nas próximas subseções são descritos os objetos existentes no .NET Framework Data Provider. 2.2.1.1.1 Connection WATSON (2002) fala que este é o primeiro objeto a ser utilizado. É responsável pela conexão com a base de dados. Cada provedor possui um nome distinto; assim, para o provedor SQL, utiliza-se o objeto SqlConnection, OracleConnection, para o provedor OdbcConnection para Oracle, o utiliza-se provedor o objeto ODBC, e OleDbConnection para o provedor OLE DB. A Figura 12 traz um exemplo com a 31 utilização do objeto Connection para o provedor SQL (que é o provedor utilizado no desenvolvimento do presente trabalho). 1: 2: ... Dim conexao As SqlConnection = New SqlConnection("Server=local;DataBase=Estagio;UID=usuario;PWD=senha") 3: Conexao.Open() 4: ... Figura 12: Exemplo de utilização do SqlConnection Como pode ser visto na Figura 12, a linha 2 trata da criação do objeto conexao do tipo SqlConnection, passando como parâmetro uma seqüência de caracteres (string), que representa: o servidor onde se encontra a fonte de dados, a base de dados que se deseja acessar e informações de acesso a essa base, como usuário e senha. Na linha 3 é executado o método Open(), que faz abertura da conexão com o banco de dados. 2.2.1.1.2 Command De acordo com WAHLIN (2003) após estabelecer a conexão com a base de dados, pode-se utilizar o objeto Command para executar comandos SQL na base de dados. Um exemplo de utilização desse objeto, é desscrito na Figura 13. 1: 2: 3: 4: 5: 6: ... Dim conexao As SqlConnection = New SqlConnection("Server=local;DataBase=Estagio;UID=usuario;PWD=senha") Sql As String = "SELECT * FROM tbAlunos" comando As SqlCommand = New SqlCommand(sql, conexao) Conexao.Open() ... Figura 13: Exemplo de utilização do objeto SqlCommand. A Figura 13 apresenta um exemplo de utilização do objeto SqlCommand. Na linha 2, cria-se a conexão com o banco de dados; Na linha 3, cria-se uma String com a instrução SQL a ser executada; Na linha 4 aparece o objeto SqlCommand, que é criado com dois parâmetros: a instrução SQL e a conexão com a base de dados. Para finalizar, na linha 5, é aberta a conexão com a base de dados, para que o comando (a instrução SQL) possa ser executado junto à base de dados. 32 2.2.1.1.3 DataReader WATSON (2002), afirma que DataReader é um objeto simples de ser utilizado para obter o resultado de uma consulta SQL. É usado somente para leitura de informações, não fornecendo formas de alterar as informações contidas na base de dados. A Figura 14 mostra a utilização de um objeto SqlDataReader. 1: 2: 3: 4: 5: 6: 7: ... Dim conexao As SqlConnection = New SqlConnection("Server=local;DataBase=Estagio;UID=usuario;PWD=senha") Sql As String = "SELECT * FROM tbAlunos" comando As SqlCommand = New SqlCommand(sql, conexao) conexao.Open() Dim reader As SqlDataReader = comando.ExecuteReader() ... Figura 14: Exemplo de utilização do objeto SqlDataReader. A Figura 14 traz um exemplo de utilização do objeto SqlDataReader. Depois de estabelecer a conexão e criar o comando a ser executado (linhas 2 a 5), é criado na linha 6 um objeto do tipo SqlDataReader que recebe o resultado da execução do método ExecuteReader() do comando. 2.2.1.1.4 DataAdapter O objeto DataAdapter é o responsável por passar os dados da fonte de dados para o DataSet (que fica desconectado da fonte de dados). É ele que cuida de todas as interações com o provedor utilizado na aplicação (WAHLIN, 2003). Um exemplo da utlização deste objeto pode ser visualizado na Figura 15. 1: ... 2: Dim conexao As SqlConnection = New SqlConnection("Server=local;DataBase=Estagio;UID=usuario;PWD=senha") 3: Conexao.Open() 4: Sql As String = "SELECT * FROM tbAlunos" 5: SqlAdapter As SqlDataAdapter = New SqlDataAdapter(sql, conexao) 6: ... Figura 15: Exemplo de utilização do objeto SqlDataAdapter. 33 De acordo com o código da Figura 15, após a realização da conexão com a base de dados e da criação de uma String contendo a instrução SQL a ser executada no banco de dados (linhas 2 a 4), na linha 5 é criado um objeto SqlDataAdapter, passando por parâmetros a instrução SQL a ser executada e a conexão com a base de dados. 2.2.1.2 DataSet DICKINSON (2002) define DataSet como sendo um componente fundamental do ADO.NET, responsável por fornecer, de forma desconectada, meios de acessar tabelas, colunas, linhas, relacionamentos e restrições de um banco de dados. Para ter acesso às informações da fonte de dados, conforme visto anteriormente, ele se utiliza do objeto DataAdapter. A seguir são apresentadas algumas propriedades de um DataSet: • DataTable: objeto chave para acessar informações de uma tabela do banco de dados, como: colunas, linhas e relacionamentos; • DataRow: objeto que possui informações sobre as linhas de uma determinada tabela; • DataColumn: objeto que possui informações sobre o esquema para cada coluna da tabela, como por exemplo o tipo de dados e o tamanho (bytes); • DataRelation: objeto que contém dados sobre os relacionamentos das tabelas, que pode ser feito entre elementos DataTables através dos objetos DataColumn. A Figura 16 apresenta um exemplo da utilização do objeto DataSet juntamente com alguns dos objetos apresentados anteriormente. 1: ... 2: Dim conexao As SqlConnection = New SqlConnection("Server=local;DataBase=Estagio;UID=usuario;PWD=senha") 3: Conexao.Open() 4: Sql As String = "SELECT * FROM tbAlunos" 5: SqlAdapter As SqlDataAdapter = New SqlDataAdapter(sql, conexao) 6: dados As DataSet = New DataSet() 7: SqlAdapter.Fill(dados,"tbAlunos") 8: ... Figura 16: Exemplo de utilização do objeto DataSet. Conforme observa-se na Figura 16, as linhas 2 a 5 são, como nos exemplos anteriores, para criar a conexão, definir a instrução SQL a ser executada e criar o objeto 34 SqlDataAdapter para passar as informações ao DataSet. Após esses passos, na linha 6 é criado o objeto DataSet e na linha 7 ele recebe os valores do SqlDataAdapter através do método Fill(), que tem como parâmetros o objeto DataSet e uma String que representa o nome do DataSet. 2.3 Bancos de Dados Relacionais De acordo com SILBERSCHATZ (1999), o modelo relacional se consolidou como o primeiro modelo de dados utilizado em aplicações comerciais. SILBERSCHATZ (1999) também diz que um banco de dados relacional é formado por uma coleção de tabelas, cada uma com um nome único. Para HEUSER (2000) uma tabela é um conjunto não ordenado de linhas (tuplas) e cada uma dessas linhas é composta por um número de campos (atributos). Um banco de dados relacional é formado por um conjunto de tabelas, onde as linhas dessas tabelas são formadas por colunas, que são os atributos da tabela. Esses atributos dizem quais as informações estão armazenadas na tabela, enquanto as linhas da tabela representam o relacionamento entre os valores dos atributos. Como exemplo será criada uma tabela com o nome “tbProduto” que armazena informações sobre os produtos de uma determinada empresa. Essa tabela possui os seguintes atributos: “código_de_barras” que será o identificador único do produto, “descrição” que conterá uma breve descrição sobre o produto e o atributo “preço” que guardará o preço do produto. Uma representação dessa tabela com algumas informações pode ser visualizada na Figura 17. Código_de_barras descrição Preço 70001256 Sabonete X 0,50 70001298 Cabide Y 3,20 70005623 Molho de tomate Z 350ml 2,80 Figura 17:Representação da tabela tbProduto em uma base de dados relacional Observando a Figura 17, percebe-se como as linhas fazem a relação entre as colunas. O produto de código_de_barras igual a ‘70005623’ é o produto com a descrição ‘Molho de tomate Z 350ml’ e com o preço ‘2,80’. Os principais bancos de dados relacionais são: 35 • Microsoft Access, que vem junto ao pacote Microsoft Office; • Oracle; • MySQL (gratuito); • PostgreSQL (gratuito); • Microsoft SQL Server, que foi utilizado no desenvolvimento do presentetrabalho. Apesar de ser um software proprietário, ou seja, não gratuito, sua utilização foi escolhida pela forma como é armazenada a estrutura de suas tabelas e relacionamentos, que serão explanadas na seção de resultados e discussões; 2.3.1 Linguagem de Consulta ao Banco – SQL DATE (2000) relata que a SQL (Structured Query Language), é a linguagem padrão para se lidar com dados relacionais. A versão original da lingagem SQL foi definida pela primeira vez no laboratório de pesquisa da IBM em San Jose na Califórnia, que hoje é conhecido como Centro de Pesquisa Almaden. Chamberlin foi o pesquisador responsável (DATE, 2000) e (SILBERSCHATZ, 1999). Inicialmente essa linguagem era chamada de SEQUEL e foi implementada como parte do projeto Sistema R no início dos anos 70. A partir daquele momento a linguagem foi evoluindo e seu nome modificado para como é conhecida hoje (SILBERSCHATZ, 1999). No ano de 1986 a ANSI (American National Standard Institute) e a ISO (International Standards Organization) publicaram os padrões a serem seguidos pela linguagem SQL, que foi também chamada de SQL-86 (SILBERSCHATZ, 1999). Em 1987 a IBM também publicou o seu próprio padrão para a linguagem, a SAA-SQL (Systems Application Architecture Database Interface). Em 1989 foi publicada uma extensão para o padrão SQL, a SQL-89. A versão padrão ANSI/ISO SQL que está em uso é a SQL-92 e está em andamento a criação do padrão SQL-3 (SILBERSCHATZ, 1999). W3SCHOOLS-SQL (2004) apresenta que sentenças e instruções SQL são utilizadas para, além de consultar, atualizar, inserir e para remover informações de uma base de dados. Para isso ela dispõe de algumas palavras-chave, tais como: • SELECT: para consultar as informações de uma base de dados; • UPDATE: para atualizar as informações da base de dados; • DELETE: para remover as informações; e, 36 • INSERT INTO: para inserir informações na base de dados. No presente trabalho será estudada, especificamente, a parte referente a consultar as informações, ou seja, a cláusula SELECT. Para consultar informações, o SELECT não funciona sozinho, ele necessita estar acompanhado, no mínimo, pela cláusula FROM. Para SILBERSCHATZ (1999), a cláusula SELECT é usada para relacionar os atributos desejados como resultado da consulta, enquanto a cláusula FROM relaciona as tabelas que serão pesquisadas na consulta. A Figura 18 indica um exemplo de uma simples consulta SQL. SELECT FROM descrição, preço TbProduto Figura 18: Consulta básica utilizando a linguagem SQL A Figura 18 traz um exemplo de consulta SQL na qual, na cláusula SELECT foram especificados os campos que seriam visualizados na consulta (descrição e preço) e na cláusula FROM foi especificada em qual tabela da base de dados esses campos seriam buscados (tbProduto, a mesma tabela demonstrada no exemplo da seção anterior). Como resultado desta consulta seria retornado o conjunto de registros apresentado na Figura 19. Descrição preço Sabonete X 0,50 Cabide Y 3,20 Molho de tomate Z 350ml 2,80 Figura 19: Tabela retornada como resultado da consulta apresentada na Figura anterior (18). Como não foi imposta uma restrição na consulta, todas as linhas foram retornadas. No caso das colunas, foram mostradas apenas as que foram solicitadas (na cláusula SELECT), ou seja, a descrição e o preço dos produtos. Caso se queira a lista de todos os atributos, pode-se descrevê-los um a um, ou simplesmente utilizar o símbolo ‘*’, que significa, na linguagem SQL, “todos os atributos”. Para se impor restrições ao resultado de uma consulta, pode ser utilizada a cláusula WHERE. Considerando a seguinte consulta: “Retorne todos os atributos da tabela tbProduto, onde o valor do código_de_barras esteja entre ‘70001000’ e ‘70006000’”, essa consulta está representada em SQL na Figura 20. 37 SELECT * FROM TbProduto WHERE código_de_barras >= 70001000 and código_de_barras <= 70006000 Figura 20: Consulta com a cláusula WHERE. Como podemos observar na Figura 20 os operadores matemáticos de comparação ‘>=’ e ‘<=’ foram utilizados. A linguagem SQL dá suporte aos operadores de comparação ‘=’, ‘<’, ‘>’, ‘>=’, ‘<=’ e ‘<>’. SILBERSCHATZ (1999) cita que estes operadores podem ser utilizados para comparar números, strings, expressões aritméticas e tipos especiais, como o tipo data. Assim como os operadores de comparação, os operadores lógicos “and” (utilizado no exemplo da Figura 19), “or” e “not” são suportados pela linguagem SQL. A linguagem SQL ainda oferece um outro operador de comparação, o operador BETWEEN, que poderia ser utilizado no exemplo anterior de forma a simplificar a consulta. A consulta utilizando o operador de comparação BETWEEN ficaria conforme pode ser visualizada na Figura 21. SELECT * FROM TbProduto WHERE código_de_barras BETWEEN 70001000 and 70006000 Figura 21: Consulta com o operador de comparação BETWEEN na cláusula WHERE. Como visto no exemplo da Figura 21, a consulta retornará as linhas da tabela tbProduto que tenham o valor do código_de_barras entre 70001000 e 70006000 da mesma forma que se estivéssemos utilizando os operadores ‘<=’ e ‘>=’. As consultas das Figuras 20 e 21 são equivalentes. Quando a consulta é executada no Banco de Dados, os dados são retornados na ordem em que foram cadastrados. Caso seja necessário algum tipo de ordenação, essa deve ser feita utilizando-se de outra cláusula disponível na linguagem SQL, a ORDER BY. SILBERSCHATZ (1999) cita que a cláusula ORDER BY faz com que os resultado da consulta apareça com uma certa ordem. Ela é posicionada no fim da consulta e nela são relacionados os campos a serem utilizados na ordenação com a devida forma de ordenação ASC ou DESC, respectivamente ascendente e descendente. 38 Um exemplo de consulta com a cláusula ORDER BY é mostrado na Figura 22, a seguir. SELECT * FROM TbProduto ORDER BY código_de_barras Figura 22: Exemplo de consulta SQL com a cláusula de ordenação ORDER BY Como pode ser visto na Figura 22, a consulta é feita especificando que o resultado deverá vir ordenado pelo código_de_barras. Como não foi especificada a forma de ordenação, o resultado será retornado com as linhas ordenadas de forma crescente. Este capítulo apresentou os conceitos necessários para o entendimento das considerações que serão apresentadas a seguir, referentes ao desenvolvimento do presente trabalho. 39 3 MATERIAL E MÉTODOS Neste capítulo, serão apresentados os detalhes referentes aos materiais e metodologia utilizados na implementação da aplicação descrita no primeiro capítulo, além dos utilizados no processo de desenvolvimento deste trabalho. 3.1 Local e Período O trabalho foi desenvolvido no Labin 5 (Laboratótio de Informática número 5) do Curso de Sistemas de Informação, no Centro Universitário Luterano de Palmas. Os trabalhos tiveram início no mês de abril de 2004 e término em julho de 2004. 3.2 Material O material utilizado pode ser dividido em três categorias: hardware, software e fontes bibliográficas. A primeira, é constituída por um micro-computador com processador Intel Pentium IV com clock de 1,7 GHz, 256 Mb de memória RAM e HD com capacidade para 40 Gb, localizado no Labin 5. Este ficou responsável pelo armazenamento das bases de dados utilizadas, e pela criação e execução da aplicação proposta neste trabalho. Os softwares utilizados foram os seguintes: • Microsoft Word, para a redação do relatório e leitura de algumas referências bibliográficas. • Microsoft SQL Server 2000, para a criação e manutenção das bases dados utilizadas. 40 • Microsoft .NET Framework 1.1, para execução das classes desenvolvidas. • Microsoft .NET Framework SDK (English) 1.1, para referência e utilização das classes providas pela plataforma .NET. • Microsoft Visual Studio .NET 2003, para codificação da aplicação. • Adobe Acrobat Reader, para a leitura de algumas referências bibliográficas. Com relação às referências bibliográficas, estas foram encontradas na biblioteca da Instituição e também na internet (principalmente). 3.3 Metodologia A implementação pode ser dividida em duas etapas: a criação do banco de dados para testes e a construção da aplicação que fará o acesso a essa base. O banco de dados foi criado em Microsoft SQL Server 2000.A linguagem de programação utilizada para a construção da aplicação foi o VB.NET. Para o desenvolvimento do trabalho foi definido inicialmente pelo professor orientador Jackson Gomes de Souza um cronograma, visualizado na Tabela 2, a seguir. Dia inicial Tarefa Aprendizado sobre DHTML: manipulação de objetos (layers, divs); movimentação dos objetos, captura da posição do mouse; encontrar 22/3/2004 uma biblioteca que facilite a utilização de código cross-browser. Escrever a referência sobre DHTML e JavaScript. Aprendizado sobre ASP.NET: processamento de dados de formulário, interação com o usuário, acesso ao banco de dados. Escrever a referência sobre ASP.NET e ADO.NET. Verificar como 29/3/2004 é possível consultar os objetos do banco de dados. Escrever uma referência sobre SQL Server (se possível, como este SGBD armazena as informações sobre os objetos do banco de dados—deve ter alguma coisa no HELP) 41 Criar uma aplicação simples, onde seja possível ao usuário: visualizar, em um formulário, a lista de tabelas e de campos de tabelas no banco de dados; escolher a tabela e os campos que deseja consultar; o sistema deve gerar uma consulta em linguagem SQL, 5/4/2004 executar a consulta junto ao SGBD e apresentar os resultados em um formato de apresentação padrão (como um relatório com colunas— que são os campos da tabela escolhida). Escrever uma referência (não muito extensa) sobre SQL. Modificar a aplicação, tornando possível ao usuário: escolher mais de uma tabela (ao escolher a tabela, o objeto que apresente a lista de campos deve ser modificado, para refletir a seleção do usuário); 12/4/2004 "incrementar" a consulta a partir de uma definição simplificada sobre as formas de filtragem de dados (WHERE), agrupamento (GROUP BY) e ordenação (ORDER BY). Modificar a aplicação, tornando possível ao usuário: visualizar, de forma gráfica (caixinhas que exibem os nomes das tabelas no topo e a lista de campos abaixo) as tabelas e os campos do banco de dados (o usuário pode ver a lista de tabelas no modo do formulário, 19/4/2004 escolher algumas delas e adicioná-las ao modelo gráfico); arrastar as caixinhas; ao selecionar um campo de uma tabela, uma parte inferior do formulário (principalmente a que for utilizada para as cláusulas WHERE, GROUP BY e ORDER BY) se modificam para aquele campo (fazer esta implementação com uma tabela somente) Modificar a aplicação, tornando possível ao usuário: a partir da visualização gráfica das tabelas, clicar ou selecionar um campo em uma tabela, arrastar até a outra tabela sobre um outro campo, a partir disso, criar um relacionamento (cláusula JOIN); o usuário deve 26/4/2004 poder escolher qual o tipo de relacionamento (lembrar que esta é uma aplicação que deve simplificar as definições técnicas, portanto, nada de perguntar ao usuário se ele deseja que seja um INNER JOIN, ou LEFT JOIN, mas apresentar-se de uma forma totalmente simplificada). 42 3/5/2004 Modificar a aplicação, tornando possível ao sistema: assim que o usuário escolher tabelas das quais deseja visualizar informações, criar o modelo gráfico já com os relacionamentos já especificados 10/5/2004 para as tabelas relacionadas; o usuário deve poder modificar o tipo do JOIN e também deve poder excluir e adicionar (semana anterior) relacionamentos. 17/5/2004 Revisão do código da aplicação; testes. 24/5/2004 Revisão final do trabalho. 31/5/2004 Revisão final do trabalho. 7/6/2004 Revisão final do trabalho. 43 4 RESULTADOS E DISCUSSÃO Como continuidade do presente trabalho, nesta seção serão expostos os resultados obtidos a partir dos estudos realizados e da implementação do sistema proposto. Esses resultados serão demonstrados através de textos e figuras relacionando as tecnologias descritas na seção de Revisão de Literatura. Para auxiliar o usuário na construção de suas consultas e execução das mesmas junto à base de dados, para o sistema foram criadas as seguintes funcionalidades: • Selecionar e adicionar tabelas à consulta; • Movimentar as tabelas adicionadas, de forma a organizar a visualização gráfica das mesmas; • Escolher os campos das tabelas que se queira consultar; • Adicionar restrições à consulta; • Editar a consulta no modo texto; • Executar a consulta na base de dados e visualizar o resultado da consulta em forma de tabela; 4.1 Modelagem do Sistema Para o desenvolvimento do sistema proposto neste trabalho, foi gerada o seguinte modelo de classes (Figura 23): 44 Figura 23: Modelo de Classes do Sistema desenvolvido nesse trabalho. A Figura 23 traz o modelo de classes desenvolvido para a implementação do presente trabalho. Para que as funcionalidades supracitadas pudessem ser oferecidas ao usuário, as seguintes classes foram desenvolvidas e/ou utilizadas: Do lado servidor (ASP.NET): • Classe Banco: Responsável por todo acesso ao Banco de Dados: o Autenticar o usuário junto ao banco de dados (estabelecer a conexão com a base de dados); o Retornar as tabelas existentes no banco de dados, assim como todas as suas características, tais como: campos, tipos dos campos e relacionamentos entre as tabelas. o Responsável por executar a consulta gerada no lado cliente e retornar o resultado ao usuário. 45 • Classe Valida: Responsável por fazer uma análise na consulta SQL antes que a mesma seja enviada à classe Banco e executada na base de dados. Essa análise serve para identificar se existem palavras não permitidas na consulta, uma vez que o usuário tem permissão de alterar a consulta no modo texto. Caso a consulta esteja correta ela pode ser executada pela classe Banco. Do lado cliente (JavaScript) • Classes fornecidas pela DynAPI: o DynLayer: Responsável pela crição das layers, vistas como tabelas pelo usuário; o DragEvent: Responsável por adicionar formas de movimentação às layers através de eventos gerados pela utilização do mouse; • Classe Consulta: responsável por manter as informações geradas pelo usuário na parte gráfica de construção da consulta e, a partir dessas informações, montar a consulta em formato texto. A qualquer modificação feita pelo usuário na parte gráfica, esta classe é acionada, para que a consulta esteja sempre atualizada de acordo com o que o usuário definiu. • Classe Tabela: Responsável por armazenar as tabelas selecionadas para a consulta e por gerar o código HTML da tabela, para que o mesmo possa ser inserido na layer que irá representar a tabela para o usuário. As classes citadas anteriormente, tanto as do lado servidor, como as do lado cliente, interagem entre si, de modo que é possível visualizar as seguintes camadas na aplicação: • Camada de Apresentação: responsável por possibilitar que o usuário monte a consulta de acordo com o que necessita. Está representada pelas classes da DynAPI, pela classe Consulta e pela classe Tabela, todas desenvolvidas através da linguagem JavaScript; • Camada de acesso a dados: é a camada responsável pela autenticação do usuário no sistema e pela execução das consultas por ele geradas. Está representada pela classe Banco; • Camada lógica de negócio: é a responsável pela ligação entre as camadas anteriores. Ela faz a validação da consulta SQL gerada pelo usuário e, caso esta 46 esteja de acordo com os padrões estabelecidos pelo sistema, envia a consulta para a camada de acesso a dados. É representada pela classe Valida. Para que a classe Banco pudesse fazer todo o acesso à base de dados e retornar as informações à camada de apresentação, em sua implementação foram utilizados recursos oferecidos pela ADO.NET. Entre eles estão: • SqlConnection: utilizado para realizar a conexão com a base de dados; • DataRow: utilizado na classe Banco para percorrer os registros retornados pela consulta; • SqlDataAdapter: utilizado para executar a consulta gerada pelo usuário e carregá-la para um DataSet; • DataSet: utilizado para retornar o resultado das consultas feitas pelo usuário na interface gráfica; utilizado também para retornar as consultas feitas pela própria aplicação, como por exemplo, a consulta que busca as tabelas existentes na base de dados. Analisando o conjunto de classes oferecidas pelo ADO.NET, não foi encontrada uma classe que retornasse o conjunto de relacionamentos existentes entre as tabelas da base de dados. Essa classe seria de grande utilidade no desenvolvimento do trabalho, visto que, por falta desta, foi necessária a criação de um método na classe banco que retornasse essa informação. Para a implementação desse método, foram utilizadas as tabelas de esquema do banco de dados, que serão apresentadas nas próximas subseções. 4.2 Interpretação do esquema relacional do Microsoft SQL Server Para fazer com que o sistema pudesse conhecer a estrutura das tabelas do banco de dados, foram utilizadas consultas SQL que acessam as tabelas do information_schema. O information_schema é formado por tabelas que armazenam o esquema das tabelas no Microsoft SQL Server. Para OLEG (2004), as tabelas do information_schema que contêm essas informações são: • CHECK_CONSTRAINTS: Contém informações sobre as constraints da base de dados; 47 • COLUMN_DOMAIN_USAGE: Contém informações sobre os tipos de dados definidos pelo usuário para as colunas das tabelas; • COLUMN_PRIVILEGES: Contém informações sobre permissão de acesso às colunas de uma tabela para determinado usuário; • COLUMNS: Contém a lista de colunas de cada tabela e cada visão da base de dados; • CONSTRAINT_COLUMN_USAGE: Contém as colunas das tabelas utilizadas na formação das constraints; • CONSTRAINT_TABLE_USAGE: Contém as tabelas utilizadas na formação das constraints; • DOMAIN_CONSTRAINTS: Contém as regras definidas para as constraints; • DOMAINS: Contém informações sobre os tipos definidos pelo usuário; • KEY_COLUMN_USAGE: Contém as colunas definidas como chave das tabelas; • PARAMETERS: Contém informações sobre a lista de parâmetros utilizados na construção de Procedimentos e de Funções definidos pelo usuário; • REFERENTIAL_CONSTRAINTS: Contém informações sobre as chaves referenciadas nas constraints; • ROUTINES: Contém informações sobre os Procedimentos e as Funções definidas pelo usuário; • ROUTINE_COLUMNS: Contém informações sobre os retornos de funções da baase de dados; • SCHEMATA: Contém informações sobre a base de dados; • TABLE_CONSTRAINTS: Contém informações sobre as constraints definidas pelo usuário; • TABLE_PRIVILEGES: Contém informações sobre o privilégio de acesso às tabelas por determinados usuários; • TABLES: Contém informações sobre as tabelas da base de dados; • VIEW_COLUMN_USAGE: Contém informações sobre as colunas utilizadas para a criação das visões da base de dados; • VIEW_TABLE_USAGE: Contém informações sobre as tabelas utilizadas para a criação das visões da base de dados; • VIEWS: Contém informações sobre as visões da base de dados. 48 Das citadas acima, as utilizadas no desenvolvimento da aplicação foram: • TABLES; • COLUMNS; • TABLE_CONSTRAINTS; • CONSTRAINT_COLUMN_USAGE; • KEY_COLUMN_USAGE; • REFERENTIAL_CONSTRAINTS; Através destas tabelas, pode-se obter do banco de dados as seguintes informações (não necessariamente na mesma ordem das citadas acima): • Nome das tabelas; • Lista de campos para cada tabela e o tipo de dados de cada campo; • Lista de campos que fazem parte da chave primária de cada tabela; • Lista de campos que fazem que são chave estrangeira em cada tabela; • Lista de relacionamentos entre as tabelas. Para exemplificar a utilização dessas informações do banco de dados, a Figura 24 traz a implementtação do método retornarTabelas(), que é responsável por retornar à aplicação a lista de tabelas existentes no banco de dados. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: Public Function retornarTabelas() As ArrayList Dim nomeTabelas() As String Dim dst As New DataTable Dim i As DataRow Me.conectar() If conexao.State <> ConnectionState.Open Then Try Me.conexao.Open() Catch ex As Exception MessageBox.Show(ex.Message) End Try End If Dim schemaDA schemaDA = New SqlDataAdapter("SELECT t.TABLE_NAME AS Nome "_ &"FROM information_schema.TABLES t "_ &"WHERE (TABLE_TYPE = 'BASE TABLE') "_ &"ORDER BY TABLE_TYPE, t.TABLE_NAME", Me.conexao) schemaDA.Fill(dst) For Each i In dst.Rows 49 20: 21: 22: 23: nomeTabelas(i) = i.Item("Nome").ToString() Next retornarTabelas = nomeTabelas End Function Figura 24: Implementação do método retornarTabelas() da classe Banco. Como visto na Figura 24, o método retornará um ArrayList contendo o nome das tabelas do banco de dados (linha 1). Na linha 2, temos a declaração da variável nomeTabelas que será retornada como resultado do método (linha 26). A linha 3 traz a declaração de um objeto DataTable, que será utilizado mais adiante para guardar os registros retornados pela consulta. Na linha 4 é declarado um objeto da classe DataRow, que irá representar as linhas retornadas na consulta. As linhas de 6 a 12 são responsáveis por abrir a conexão feita na linha 5. Nas linhas de 13 a 17 é criado um objeto do tipo SqlDataAdapter com a consulta que lê informações sobre as tabelas existentes no banco de dados com o qual a aplicação está conectada. Na linha 18, o objeto do tipo DataTable declarado anteriormente, recebe o resultado da consulta. Nas linhas de 19 a 21 há o preenchimento do Array de String que representa os nomes das tabelas, que são retornados com o resultado da consulta. Na linha 22, é retornado o ArrayList que contém os nomes das tabelas da base de dados e, na linha 23, o método é finalizado. 4.3 Interface gráfica Para a criação da interface gráfica foram utilizados Web Controls, objetos da DynAPI e a DHTML, com a utilização de elementos HTML e códigos JavaScript. O resultado final da interface do sistema pode ser visualizado na Figura 25. 50 1 2 3 4 Figura 25: Interface gráfica do sistema. Como pode ser observado na Figura 25, a interface do sistema está dividida em quatro partes: 1) Área para adição das layers (tabelas selecionadas pelo usuário); 2) Área com as tabelas existentes na base de dados e com as tabelas pelo usuário adicionadas à consulta; 3) Área com os campos já adicionados à consulta; 4) Área com a consulta em modo texto; A relação entre as partes da interface é a seguinte: • Quando a página é carregada, um objeto da classe Banco busca na base de dados todas as tabelas, os campos de cada tabela e os relacionamentos de cada tabela. Os 51 nomes das tabelas são adicionados a uma lista (objeto ListBox) que fica visível ao usuário. Já os campos e os relacionamentos também são carregados em listas, porém estas ficam escondidas na página para que apenas as classes JavaScript tenham acesso a essas informações e o usuário não as visualize; • Uma vez carregadas essas listas, o usuário pode começar a montar sua consulta; • À partir da lista com as tabelas da base de dados, o usuário pode selecionar a tabela que deseja adicionar à consulta e clicar no botão "Adicionar". A tabela por ele escolhida será adicionada à outra lista (a de tabelas selecionadas) e uma layer com o nome da tabela e o nome de seus respectivos campos será adicionada à parte 1 da interface; quando o usuário não mais desejar utilizar esta tabela, ele pode selecionála na lista de tabelas já adicionadas e clicar no botão "Remover" fazendo, assim, com que todas as informações referentes a esta tabela sejam retiradas da interface gráfica; • Uma vez que a layer foi criada, o usuário pode selecionar os campos da tabela e esses vão sendo adicionados à parte 3 da interface, onde poderão ser definidos os critérios para a consulta; • A cada ação do usuário, uma nova consulta é gerada utilizando todas as informações disponíveis na interface; essa nova consulta é visualizada pelo usuário na parte 4 da interface. Os passos para a geração da consulta serão mais detalhados na próxima sub-seção. 4.4 Geração da consulta SQL A geração da consulta SQL, através da interface gráfica, foi possível graças à utilização da classe Consulta, que acessa todas as informações das tabelas adicionadas pelo usuário, assim como dos campos que o mesmo selecionou para serem consultados. Para cada campo selecionado, é criada uma linha na parte 3 da interface gráfica para que o usuário possa adicionar um critério, uma ordenação e até mesmo determinar se ele deseja ou não visualizar esse campo no resultado da consulta. Para montar a consulta é feita, na função fn_montarConsulta(), uma estrutura de repetição entre as linhas que foram criadas a cada campo das tabelas que o usuário escolheu para a consulta. Através dessa repetição são montadas as cláusulas SELECT, e parte da cláusula WHERE. Para montar a cláusula FROM, é utilizada a função 52 fn_montarFrom(), que percorre, também através de uma estrutura de repetição, todas as layers adicionadas à interface gráfica, percorrendo assim as tabelas adicionadas à consulta. Uma outra parte da cláusula WHERE, a que é responsável por montar as restrições que vão indicar os relacionamentos entre as tabelas, é feita ainda na função fn_montarConsulta(), porém, antes de começar a estrutura de repetição que irá montar as cláusulas citadas anteriormente. A Figura 26 apresenta o trecho de código responsável por montar a cláusula FROM da consulta SQL e apresentá-la ao usuário na forma de texto. 1: function fn_montarFrom(){ 2: var consFrom = "", tabela1, tabela2, t1, t2, relacao, tabela = ""; 3: for (var i = 0; i < lyrPai.children.length; i++){ 4: tabela = ""; 5: if (i > 0) 6: consFrom += ", "; 7: tabela = lyrPai.children[i].id; 8: consFrom += tabela; 9: } 10: return consFrom; 11: } Figura 26: Código responsável por montar a cláusula FROM a partir da interface gráfica De acordo com o código apresentado pela Figura 26, na linha 1 tem-se a assinatura da função. A linha 2 declara as variáveis necessárias para a construção da cláusula FROM. A linha 3 inicia a principal etapa dessa função, que é a estrutura de repetição que irá percorrer as layers adicionadas à interface gráfica, ou seja, irá percorrer as tabelas. Na linha 4 a variável tabela é inicializada com "" (vazio) a cada repetição. Na linha 5 é feito um teste para saber se já não é a primeira das tabelas, para daí poder, na linha 6, adicionar uma ' ,'(vírgula) à cláusula FROM. A linha 7 faz com que a variável tabela receba a propriedade ' id'da layer em questão – essa propriedade contém o nome da tabela. A linha 8 adiciona o valor de tabela à variável consFrom, que conterá o valor final da cláusula. Na linha 10, a cláusula é retornada e finalmente na linha 11, a função é encerrada. Para as demais linhas de código, o funcionamento é semelhante, variando apenas os componentes da interface que serão acessados. 4.5 Comunicação com o Banco de Dados e Exibição de Registros 53 Após a criação da consulta, o usuário pode executá-la junto à base de dados. Para que essa consulta seja executada, primeiramente ela é validada pelo método validar() da classe Valida. Caso a consulta seja válida, ela é enviada ao método executarConsulta() da classe Banco. Nesse método a consulta é executada na base de dados e seus registros adicionados a um objeto DataSet. Esse objeto que contém os registros resultantes da execução da consulta é retornado à interface gráfica e lá é adicionado a um componente ASP.NET DataGrid. Esse DataGrid é o local onde o resultado da consulta será exibido ao usuário em forma de uma tabela, ou seja, os campos por ele selecionados serão os campos da tabela e as linhas da tabela serão formadas pelos valores encontrados na base de dados que obedeçeram às restrições estabelecidas pelo usuário. O código responsável por fazer com que a consulta seja exibida ao usuário pode ser visto na Figura 27 logo a seguir. 1: Private Sub btnConsultar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConsultar.Click 2: Dim valida As Valida 3: If (valida.validar(Me.txtConsulta.Value)) Then 4: Dim banco As New Banco 5: Dim dst As DataSet 6: dst = banco.executarConsulta(Me.txtConsulta.Value) 7: dtgResultado.DataSource = dst.Tables("Resultado").DefaultView 8: dtgResultado.DataBind() 9: End If 10: End Sub Figura 27: Trecho de código responsável por apresentar ao usuário o resultado da consulta. Como pode se observar na Figura 27, o resultado da consulta é exibido ao usuário em um objeto DataGrid denominado dtgResultado. Na linha 1 tem-se a assinatura do método que irá apresentar o resultado da consulta ao usuário. A linha 2 é responsável por criar uma instância da classe Valida, que será responsável por validar a consulta. Na linha 3 é executado o método validar() do objeto valida, passando como parâmetro a consulta criada pelo usuário através da interface gráfica. Caso a consulta seja válida, na linha 4 é criada uma instância da classe Banco e na linha 5 um DataSet. O objeto banco será responsável por executar a consulta na base de dados (através de método executarConsulta()) e o DataSet irá receber o retorno da execução desse método (linha 6). A linha 7 é responsável por atribuir a tabela do DataSet à propriedade 54 DataSource de dtgResultado (objeto DataGrid onde o usuário irá visualizar o resultado da consulta). E, finalmente, a linha 8 é responsável por exibir a tabela no DataGrid, através do método DataBind(). Após a execução da consulta, o usuário poderá visualizar o resultado da consulta por ele criada através da interface gráfica disponibilizada pelo sistema criado nesse trabalho. Após a visualização dos resultados obtidos com a implementação do sistema, a próxima seção tratará das considerações finais sobre o trabalho e propostas de trabalhos futuros. 55 5 CONSIDERAÇÕES FINAIS Através da utilização do sistema desenvolvido neste trabalho, mesmo usuários com pouco ou nenhum conhecimento de SQL, poderão efetuar consultas em bases de dados dispostas na web, visto que para a criação das consultas, o sistema oferece ao usuário uma interface gráfica de fácil manuseio; e tendo o usuário facilidade na criação de suas consultas, ele pode ter acesso a informações do modo que melhor satisfaça as suas necessidades. Essa facilidade de utilização da interface gráfica é conseguida com a utilização de DHTML na geração gráfica de consultas, facilitando a geração do código SQL. A utilização da DynAPI para a construção dos códigos JavaScript responsáveis pela manipulação das layers faz com que a aplicação seja suportada por vários Browsers, visto a DynAPI é uma API cross-browser. Algumas das dificuldades encontradas durante o desenvolvimento deste trabalho estão diretamente ligadas a encontrar subsídios necessários para a implementação do sistema. Podem ser citadas: a falta de uma API que recuperasse os relacionamentos entre as tabelas do banco de dados e o tempo gasto para encontrar referências de como funciona o modelo de objetos do SQL Server. Com base nos resultados obtidos, pode-se concluir que os objetivos do sistema foram alcançados. O usuário pode: adicionar à interface gráfica as tabelas de uma base de dados, selecionar campos das tabelas adicionadas e atribuir critérios a esses campos, assim como definir tipos de ordenação e aliases para cada campo. A consulta SQL é montada a cada alteração do usuário na interface gráfica. Um ponto da implementação que não ficou adequado da forma proposta inicialmente, foi a parte responsável por montar a cláusula FROM: a idéia inicial era de que essa cláusula contivesse os relacionamentos entre as tabelas através de cláusulas JOINs. 56 Ainda, baseado nos resultados obtidos, durante o desenvolvimento do sistema (citados na seção anterior), pode-se concluir que as funcionalidades previstas para o sistema foram implementadas: o sistema traz ao usuário a lista de tabelas do banco de dados; à medida em que o usuário seleciona uma tabela para a consulta, o sistema cria uma representação gráfica dessa tabela, juntamente com seus campos e à medida em que os campos são selecionados para a consulta, novas opções são dadas ao usuário para estabelecer os critérios de sua consulta. A cada alteração feita pelo usuário na interface, seja adicionando e/ou removendo tabelas, selecionando campos, ou definindo critéios, a consulta SQL é modificada para ficar de acordo com o estado da interface. 57 6 TRABALHOS FUTUROS Como proposta de trabalhos futuros pode se refazer o método que monta a consulta, adicionando a este, a idéia de fazer com que os relacionamentos, ao invés de serem representados na cláusula WHERE, passem a ser adicionados à cláusula FROM. Estando na cláusula FROM, haveria a necessidade de inserção dos JOINs (INNER, LEFT, RIGHT e FULL) que são responsáveis por estabelecer o relacionamento nessa cláusula. Além dessa mudança, é proposta também a adição de alguns recursos à construção da consulta, como por exemplo, possibilidade de se definir mais de um critério para cada campo, e adicionar à consulta, além dos relacionamentos existentes na base de dados, também os relacionamentos criados pelo próprio usuário. Todas alterações feitas pelo usuário na interface gráfica, são diretamente enviadas para a consulta em modo texto, mas as alterações da consulta SQL feitas pelo usuário não são refletidas na interface gráfica; sendo assim, um outro ponto importante dos trabalhos futuros é desenvolver esta funcionalidade de alterar a interface à partir da consulta textual. Também como continuação a este trabalho, existe a proposta de não mais retornar ao usuário o resultado da consulta por ele gerada em forma de tabela. A proposta é o desenvolvimento de um sistema maior, que será utilizado para customização de relatórios. Nesse sistema o usuário, além de montar a consulta que deseja a partir da interface gráfica (contando com os demais recursos citados anteriormente), também poderá escolher a forma de visualização do resultado da consulta, montando o padrão visual do relatório desejado. Outra modificação proposta é a escolha por parte do usuário de quais painéis deseja visualizar durante a construção da consulta, ou seja, visualizar apenas a parte gráfica, apenas a parte textual da consulta ou ambas as partes. Para que o trabalho funcione também com outros servidores de banco de dados, como o Oracle e o MySql por exemplo, terão de ser realizados novos estudos para entender 58 como é representado o modelo de objetos (tabelas, campos e relacionamentos) desses servidores. 59 REFERÊNCIAS BIBLIOGRÁFICAS (AÉCE, 2004) Israel Aéce, Linha de Código. Disponível em: <http://www.linhadecodigo.com.br/artigos.asp?id_ac=342&pag=1> Acesso em: 23 de jun. 2004. (D’ANGELO-1274, 2003) D’ANGELO, Fernando. Microsoft .NET A Plataforma Java da Microsoft. Disponível em: <http://www.aspbrasil.com.br/tutoriais/detalhes.aspx?codConteudo=1274> Acesso em: 18 de jun. de 2004. (D’ANGELO-1291, 2003) D’ANGELO, Fernando. .NET Framework e ASP.NET. Disponível em: <http://www.aspbrasil.com.br/tutoriais/detalhes.aspx?codConteudo=1291> Acesso em: 18 de jun. de 2004. (DATE, 2000) DATE, C. J. Introdução a Sistemas de Banco de Dados. Rio de Janeiro: Campus, 2000. (DICKINSON, 2002) DICKINSON, Paul. et al. Profissional ADO.NET Programando. Rio de Janeiro: Editora Alta Books, 2002. (DYNAPI, 2004) DynAPI - Cross-Browser DHTML Library. Disponível em: <http://dynapi.sourceforge.net/dynapi/> Acesso em: 03 de abr. 2004. (FEATHER, 1997) FEATHER, Stephen. JavaScript em exemplos. São Paulo: Makron Books, 1997. (HEUSER, 2000) HEUSER, Carlos Alberto. Projeto de Banco de Dados. 3ª ed. Porto Alegre: Sagra Luzzatto, 2000. (KANTOR, 2003) KANTOR, Peter L. JavaScript: The Browser Object Model. 2003. Disponível em: <http://academ.hvcc.edu/~kantopet/javascript/index.php?page=the+js+bom>. Acesso em 26 de jun. 2004. (MACHADO, 1996) MACHADO, Felipe Nery Rodrigues. Projeto de Banco de Dados: uma visão prática. São Paulo: Érica, 1996. (MACDONALD, 2002) MACDONALD, Matthew. O livro de VB.NET. Rio de Janeiro: Editora Ciência Moderna Ltda., 2002. (MSDN, 2004) Overview of the .NET Framework. Disponível em: <http://msdn.microsoft.com/library/default.asp>. Acesso em 04 de jun. 2004. (MONO, 2004) Mono. Disponível em: <http://www.go-mono.com/>. Acesso em 25 de jun. 2004. (OLEG, 2004) The Code Project. Browsing MS SQL Server Desktop Engine using Information Schema. Disponível em: <http://www.codeproject.com/cs/database/MSDEInfoSchema.asp>. Acesso em 11 de jun. 2004. (OZEMAIL, 2004) OZEMAIL. Disponível em: < http://members.ozemail.com.au/~phoenix1/html/navobj.htm#1006931>. Acesso em 26 de jun. 2004. 60 (PAYNE, 2001) PAYNE, Chris. Aprenda em 21 dias ASP.NET. Rio de Janeiro: Campus, 2001. (SILBERSCHATZ, 1999) SILBERSCHATZ, Abraham, KORTH, Henry F. E SUDARSHAN, S. Sistema de Banco de Dados. 3ª ed. São Paulo: Makron Books, 1999. (SILVA, 2001) SILVA, Osmar J. DHTML: Estilos e Conteúdo Dinâmico. São Paulo, Editora Érica, 2001. (W3C, 2004) The global structure of an HTML document. Disponível em: <http://www.w3.org/TR/REC-html40/struct/global.html#h-7.5.4>. Acesso em 26 de jun. 2004. (W3SCHOOLS-ASP, 2004) Introduction to ASP. Disponível em: <http://www.w3schools.com/asp/default.asp>. Acesso em 8 de jul. 2004. (W3SCHOOLS-JS, 2004) JavaScript Introduction. Disponível em: <http://www.w3schools.com/js/js_intro.asp> Acesso em: 01 de abr. 2004. (W3SCHOOLS-SQL, 2004) Refsnes Data, SQL Introduction. Disponível em: <http://www.w3schools.com/sql/sql_intro.asp>. Acesso em: 02 de abr. 2004. (WAHLIN, 2003) WAHLIN, Dan. XML e ASP.NET para desenvolvedores. São Paulo, Pearson Education do Brasil, 2003. (WATSON, 2002) WATSON, Karli. Biginning C# Programando. São Paulo: Pearson Education do Brasil, 2002. 61 APÊNDICE A - Código referente à classe Banco 1: Imports System 2: Imports System.Data 3: Imports System.Data.SqlClient 4: 5: Public Class Banco 6: 7: Private conexao As SqlConnection 8: Private strCon As String 9: 10: Public Sub conectar() 11: strCon = "Database=Teste;Server=Labin501;UID=sa;PWD=1234" 12: conexao = New SqlConnection(strCon) 13: End Sub 14: 15: Public Function executarConsulta(ByVal strSql As String) As DataSet 16: Dim dst As DataSet 17: dst = New DataSet 18: Me.conectar() 19: If conexao.State <> ConnectionState.Open Then 20: Try 21: Me.conexao.Open() 22: Catch ex As Exception 23: Exit Function 24: End Try 25: End If 26: Dim sqlDA As SqlDataAdapter 27: sqlDA = New SqlDataAdapter(strSql, conexao) 28: sqlDA.Fill(dst, "Resultado") 29: conexao.Close() 30: executarConsulta = dst 31: End Function 32: 33: Public Function retornarTabelas() As ArrayList 34: Dim nomeTabelas As ArrayList = New ArrayList 35: Dim dst As New DataTable 36: Dim i As DataRow 37: Me.conectar() 38: If conexao.State <> ConnectionState.Open Then 39: Try 40: Me.conexao.Open() 41: Catch ex As Exception 42: Exit Function 43: End Try 44: End If 45: Dim schemaDA 46: schemaDA = New SqlDataAdapter("SELECT t.TABLE_NAME AS Nome FROM information_schema.TABLES t WHERE (TABLE_TYPE = 'BASE TABLE') ORDER BY TABLE_TYPE, t.TABLE_NAME", Me.conexao) 47: schemaDA.Fill(dst) 48: For Each i In dst.Rows 49: nomeTabelas.Add(i.Item("Nome").ToString()) 50: Next 51: retornarTabelas = nomeTabelas 52: 62 53: 54: 55: End Function Public Function retornarColunas(ByVal nomeTabela As String) As ArrayList 56: Dim nomeColunas As ArrayList = New ArrayList 57: Dim dst As New DataTable 58: Dim i As DataRow 59: Me.conectar() 60: If conexao.State <> ConnectionState.Open Then 61: Try 62: Me.conexao.Open() 63: Catch ex As Exception 64: Exit Function 65: End Try 66: End If 67: Dim strSql As String 68: strSql = "SELECT t.TABLE_NAME AS Nome, c.COLUMN_NAME AS Coluna, c.DATA_TYPE AS Tipo " 69: strSql &= "FROM information_schema.COLUMNS c INNER JOIN " 70: strSql &= " information_schema.TABLES t ON c.TABLE_NAME = t.TABLE_NAME AND c.TABLE_CATALOG = t.TABLE_CATALOG AND " 71: strSql &= " c.TABLE_SCHEMA = t.TABLE_SCHEMA " 72: strSql &= "WHERE (t.TABLE_NAME = '" & nomeTabela & "')" 73: strSql &= "ORDER BY c.ORDINAL_POSITION" 74: Dim schemaDA 75: schemaDA = New SqlDataAdapter(strSql, Me.conexao) 76: schemaDA.Fill(dst) 77: For Each i In dst.Rows 78: nomeColunas.Add(i.Item("Coluna").ToString() & "-" & i.Item("Tipo").ToString()) 79: Next 80: retornarColunas = nomeColunas 81: 82: End Function 83: 84: Public Function retornarRelacionamentos(ByVal nomeTabelaPrimaria As String, ByVal nomeTabelaReferencia As String) As ArrayList 85: Dim nomeRelacionamentos As ArrayList = New ArrayList 86: Dim dst As New DataTable 87: Dim i As DataRow 88: Me.conectar() 89: If conexao.State <> ConnectionState.Open Then 90: Try 91: Me.conexao.Open() 92: Catch ex As Exception 93: Exit Function 94: End Try 95: End If 96: Dim strSql As String 97: strSql = "SELECT primarias.Tabela + '.' + primarias.Coluna + ' = ' + referencias.Tabela + '.' + referencias.Coluna AS Referencia " 98: strSql &= "FROM (SELECT DISTINCT " 99: strSql &= " r.CONSTRAINT_NAME AS NomeChaveEstrangeira, r.UNIQUE_CONSTRAINT_NAME AS NomeChavePrimaria, k.COLUMN_NAME AS Coluna, " 63 100: strSql &= " ORDINAL_POSITION AS Ordem, c.TABLE_NAME AS Tabela " 101: strSql &= " FROM information_schema.REFERENTIAL_CONSTRAINTS r INNER JOIN " 102: strSql &= " information_schema.KEY_COLUMN_USAGE k ON r.CONSTRAINT_NAME = k.CONSTRAINT_NAME INNER JOIN " 103: strSql &= " information_schema.CONSTRAINT_COLUMN_USAGE c ON r.CONSTRAINT_NAME = c.CONSTRAINT_NAME " 104: strSql &= " WHERE (k.TABLE_NAME = '" & nomeTabelaReferencia & "')) referencias INNER JOIN " 105: strSql &= " (SELECT DISTINCT tc.TABLE_NAME AS Tabela, tc.CONSTRAINT_NAME AS NomeChavePrimaria, ccu.COLUMN_NAME AS Coluna " 106: strSql &= " FROM information_schema.TABLE_CONSTRAINTS tc INNER JOIN " 107: strSql &= " information_schema.CONSTRAINT_COLUMN_USAGE ccu ON tc.TABLE_NAME = ccu.TABLE_NAME AND " 108: strSql &= " tc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME " 109: strSql &= " WHERE (CONSTRAINT_TYPE = 'PRIMARY KEY') AND (tc.TABLE_NAME = '" & nomeTabelaPrimaria & "')) primarias ON " 110: strSql &= " referencias.Coluna = primarias.Coluna" 111: Dim schemaDA 112: schemaDA = New SqlDataAdapter(strSql, Me.conexao) 113: schemaDA.Fill(dst) 114: For Each i In dst.Rows 115: nomeRelacionamentos.Add(i.Item("Referencia").ToString()) 116: Next 117: retornarRelacionamentos = nomeRelacionamentos 118: End Function 119: 120: End Class 64 APÊNDICE B - Código referente à classe Valida 1: Imports System 2: 3: Public Class Valida 4: 5: Private consulta As String 6: 7: Public Function validar(ByVal strSql As String) As 8: Me.consulta = strSql 9: Me.consulta = Me.consulta.ToUpper 10: If (Me.consulta = "") Then 11: Return False 12: End If 13: If (Me.consulta.IndexOf("DELETE", 0) <> -1) 14: Return False 15: End If 16: If (Me.consulta.IndexOf("CREATE", 0) <> -1) 17: Return False 18: End If 19: If (Me.consulta.IndexOf("INSERT", 0) <> -1) 20: Return False 21: End If 22: Return True 23: 24: End Function 25: 26: End Class Boolean Then Then Then 65 APÊNDICE C - Código referente à classe Consulta 1: 2: 3: 4: 5: 6: 7: 8: function Consulta(){ this.consulta = ""; this.montarConsulta = fn_montarConsulta; this.montarFrom = fn_montarFrom; } function fn_montarFrom(){ var consFrom = "", tabela1, tabela2, t1, t2, relacao, tabela = ""; 9: for (var i = 0; i < lyrPai.children.length; i++){ 10: tabela = ""; 11: if (i > 0) 12: consFrom += ", "; 13: tabela = lyrPai.children[i].id; 14: consFrom += tabela; 15: } 16: return consFrom; 17: } 18: 19: function fn_montarConsulta(){ 20: var tabela = document.getElementById('tblRestricoes'); 21: var relacionamentos = document.getElementById('listaRelacionamentos'); 22: var clausula = "", tabela1, tabela2; 23: var linhas = tabela.rows.length; 24: var consSelect = "SELECT "; 25: var consFrom = "\nFROM "; 26: var consWhere = "\nWHERE "; 27: var consOrderBy="\nORDER BY "; 28: var clausula, campo, nomeCampo, nomeWhere, criterio, criterios, orderby, ordenados, exibir, ahCriterio, ahOrderBy, exibidos, adicionarWhere, adicionarOrderBy; 29: adicionarWhere = adicionarOrderBy = false; 30: exibidos = ordenados = criterios = 0; 31: campos = ""; 32: //montar WHERE 33: for (var l = 0; l < lyrPai.children.length - 1; l++){ 34: for (var j = l + 1; j < lyrPai.children.length; j++){ 35: clausula = ""; 36: tabela1 = lyrPai.children[l].id; 37: tabela2 = lyrPai.children[j].id; 38: for (var k = 0; k < relacionamentos.length - 1; k++){ 39: relacao = relacionamentos.options[k].text.split(" = "); 40: t1 = relacao[0]; 41: t2 = relacao[1]; 42: t1 = t1.split("."); 43: t2 = t2.split("."); 44: nomet1 = t1[0]; 66 45: 46: nomet2 = t2[0]; if ((nomet1 == tabela1 && nomet2 == tabela2) || (nomet1 == tabela2 && nomet2 == tabela1)){ 47: if (criterios > 0){ 48: clausula += " AND " 49: } 50: clausula += "("+relacionamentos.options[k].text+")"; 51: criterios++; 52: adicionarWhere = true; 53: } 54: } 55: consWhere += clausula; 56: } 57: } 58: //fim parcial montar WHERE 59: 60: for (var i = 1; i < linhas; i++){ 61: //montar SELECT 62: exibir = tabela.rows[i].cells[2].innerHTML.indexOf('CHECKED'); 63: campo = ""; 64: if (exibir != -1){ 65: exibidos++; 66: if (exibidos > 1) 67: consSelect += ", "; 68: campo = tabela.rows[i].cells[0].innerHTML; 69: nomeCampo = campo; 70: nomeWhere = nomeCampo 71: var finalAlias = tabela.rows[i].cells[1].innerHTML.indexOf('>'); 72: var valorAlias = tabela.rows[i].cells[1].innerHTML.indexOf('value='); 73: if (valorAlias != -1){ 74: nomeCampo = tabela.rows[i].cells[1].innerHTML.substring(valorAlias+6,finalAlias); 75: campo += " AS " + tabela.rows[i].cells[1].innerHTML.substring(valorAlias+6,finalAlias); 76: } 77: } 78: consSelect += campo; 79: //fim montar SELECT 80: //continuação montar WHERE 81: ahCriterio = tabela.rows[i].cells[4].innerHTML.indexOf('value='); 82: criterio = ""; 83: tipo = linhas.name; 84: if (ahCriterio != -1){ 85: criterios ++; 86: adicionarWhere = true; 87: if (criterios > 1) 88: criterio += " AND "; 89: var finalCriterio = tabela.rows[i].cells[3].innerHTML.indexOf('>'); 90: var sinalCriterio = document.getElementById("select_sinal"); 67 91: var sinal = sinalCriterio.options[sinalCriterio.selectedIndex].text 92: if (tipo == "nvarchar" || tipo == "char" || tipo == "varchar" || tipo == "datetime" || tipo == "smalldatetime"){ 93: criterio += "(" + nomeWhere + " "+sinal+" '" + tabela.rows[i].cells[4].innerHTML.substring(ahCriterio+6,finalCriterio ) + "')"; 94: } 95: else{ 96: criterio += "(" + nomeWhere + " "+sinal+" " + tabela.rows[i].cells[4].innerHTML.substring(ahCriterio+6,finalCriterio ) + ")"; 97: } 98: consWhere += criterio; 99: } 100: //fim montar WHERE 101: //montar ORDER BY 102: var selecao = document.getElementById('select_sinal_'+campo); 103: if (selecao.selectedIndex >= 0){ 104: var selecionado = selecao.options[selecao.selectedIndex].text 105: orderby = ""; 106: if (selecionado != ""){ 107: adicionarOrderBy = true; 108: ordenados++; 109: if (ordenados > 1) 110: orderby += ", " 111: if (selecionado == "Cresc"){ 112: orderby += nomeWhere + " asc"; 113: } 114: if (selecionado == "Decresc"){ 115: orderby += nomeWhere + " desc"; 116: } 117: consOrderBy += orderby; 118: } 119: } 120: //fim montar ORDER BY 121: } 122: if (consSelect == "SELECT "){ 123: consSelect += '*'; 124: } 125: //montar FROM 126: consFrom += this.montarFrom(); 127: //fim montar FROM 128: 129: var x = document.getElementById('txtConsulta'); 130: this.consulta = consSelect + consFrom; 131: if (adicionarWhere) 132: this.consulta += consWhere; 133: if (adicionarOrderBy) 134: this.consulta += consOrderBy; 68 135: 136: x.value = this.consulta; } 69 APÊNDICE D - Código referente à classe Tabela 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: function Tabela(nome, campos, ordem){ this.nome = nome; this.campos = campos; this.ordem = ordem; this.getNome = fn_getNome; this.getOrdem = fn_getOrdem; this.getTabela = fn_getTabela; this.getCampos = fn_getCampos; this.setCampos = fn_setCampos; } function fn_getNome(){ return this.nome; } function fn_getOrdem(){ return this.ordem; } function fn_getTabela(){ var html = "", campo; html = "<font style='FONT-WEIGHT: normal; FONT-SIZE: 4px; FONT-FAMILY: Arial, Verdana, Tahoma; FONT-VARIANT: normal; TEXT-DECORATION: none'><table bgcolor='white' border='1'><tr><td><table bgcolor='blue' width='100%'><tr><td><b><font color='white'>"+this.getNome()+this.getOrdem()+"</font></b></td></tr>< /table></td></tr>"; 23: for(var i = 0; i < this.campos.length; i++){ 24: html += "<tr><td><input type='checkbox' value='"+this.campos[i][0]+"' id='"+this.nome+'.'+this.campos[i][0]+"' name='"+this.campos[i][0]+"' title='"+this.campos[i][1]+"' onclick='criarLinha(this)'>"+this.campos[i][0]+"</td></tr>"; 25: } 26: html += "</table></font>"; 27: return html; 28: } 29: 30: function fn_getCampos(){ 31: var campos = ""; 32: for (var i=0; i<this.campos.length; i++){ 33: campos += this.campos[i]; 34: } 35: return campos; 36: } 37: 38: function fn_setCampos(campos){ 39: this.campos = campos; 40: }