Arquivo para Junho, 2008

Visual Studio + NHibernate: Construindo aplicações em camadas – (cont. IV)

No post anterior criamos as classes e os mapeamento O/R do Hibernate. Vimos que essas classes farão o papel de transferir dados entre as camadas. Neste post vamos construir os DAO´s. Vamos definir os componentes que farão acesso ao banco de dados, ou seja, os DAO´s.

Vamos falar um pouco sobre alguns detalhes importantes neste processo. No post anterior indicamos um material sobre conhecimentos preliminares em relação ao Hibernate. Importante ter lido antes de continuar.

Nunca tive muita afinidade com a arquitetura cliente/servdor. Aquela onde existe um servidor de banco instalado em algum lugar da rede e as aplicações acessam diretamente este servidor fazendo requisições e persistindo dados. Esse processo é muito comum em Delphi e Visual Basic. Os programadores constroem um executável, embuntindo as regras de negócio e os comandos SQL no programa. Sempre achei isso meio complicado de gerenciar. E, de certa forma, é mesmo. Controle de transação, travamento de linhas, várias máquinas com o mesmo executável instalado e acessando o mesmo banco, etc. passam a ser preocupações do desenvolvedor que deve embutir soluções no programa. Mesmo usando o Delphi eu preferia separar alguns papéis. Eu fazia assim: a aplicação era responsável apenas por solicitar e exibir dados so servidor. As procedures do banco eram responsáveis para incluir, alterar e excluir dados (regras de negócio e DAO). Nenhuma aplicação poderia efetuar inserções, alterações ou deleções diretamente nas tabelas. Essas operações tinham que passar pelas procedures. As aplicações parametrizava dados e passava para a procedure. A aplicação permanecia aguardando o final da execução da procedure para saber se houve algum problema ou tudo foi realizado com sucesso. Nas procedures eram definidas regras da aplicação: validações, integridades, restrições, procedures paralelas (nada de triggers), etc. Inclusive acho isso muito bom. Não existe nada mais rápido pra banco de dados do que procedures. Eu disse NADA!!!!!!!!

Como nada é perfeito, tem um problema: se mudar a aplicação para outro banco as procedures teriam que ser reescritas!!!! Eu tinha uma aplicação mediana em SQL Server com mais de 200 procedures que teria que migrar para Oracle. Sem chances reescrever as procedures novamente. E se tivesse que mudar pra outro banco? Reescrever tudo outra vez?.

Neste cenário entrou o Hibernate! Com ele foi possível ganhar indepêndencia de banco de dados. Mas nem tudo são flores. As procedures do banco geram pouco tráfego de rede. O Hibernate gera auto nível de tráfego. Por isso é importante ter cuidado ao utiliza-lo. Sem falar em outras situações: gerenciamento de sessão, conectividade com outros bancos, HQL (o SQL do Hiberante), configurações, etc. Por tudo isso é importante planejar bem o seu uso. Dediquei um pouco do meu tempo a pesquisar e planejar. Construí uma biblioteca que gerencia inúmeras situações que acabam sendo repetitivas nas aplicaçãoes com Hibernate. Eu a chamei de Regisoft.Camadas. Ela faz parte de um pacote (Regisoft Library.NET) com outras bilbiotecas que utilizo no processo de desenvolvimento. Veja as classes que a biblioteca Regisoft.Camadas possui:

  1. NHibernateHelper – (Regisoft.Camadas.NHibernateHelper) Responsável por configurar e gerenciar o Hibernate dentro da aplicação. Inicialização das classes de mapeamento, gerenciamento da sessão, conectividade com um ou vários bancos de dados ao mesmo tempo são responsabilidades desta classe. Não precisa ser instanciada nem utilizada diretamente. Uma outra classe chamada BaseDAO fará uso desta classe internamente.
  2. BaseDAO – Todos os DAO´s devem herdar dessa classe abstrata. É um DAO genérico que é responsável por dar suporte, através de seus métodos e propriedades, ás operações envolvendo persistência: inserções, alterações, exclusões, transações, seleção de dados, validação de campos not-null, controle de objetos persistentes e transientes, verificação de integridade antes de uma exclusão e outras mais. Existe uma versão bem completa usando o Generic da versão .NET 3.5 (Regisoft.Camdas.Generic.BaseDAO<T,ID> ) e uma versão descontinuada sem Generic (Regisoft.Camadas.BaseDAO). A versão sem Genéric existe por compatibilidade retroativa. Aplicações desenvolvidas em .NET 1.1 ou anterior utilizam esta versão (não valia a pena mudar).

Eu utilizo esta biblioteca em TODAS as aplicações que desenvolvo. Ela me permite abstrair da problemática do Hibernate. Não será diferente na nossa aplicação de Agenda Telefônica On-Line. Vamos gerar nossos DAO´s herdando da classe abstrata dessa biblioteca. Quem desejar escrever seu próprio BaseDAO ou sua própria biblioteca fique a vontade. Tem um post aqui que fala sobre as funcionalidades básicas que todo DAO genérico tem que ter. Leia mais… Uma novidade: o nosso BaseDAO também pode ser configurado para trabalhar numa arquitetura que faz uso de um ou mais servidores de aplicações. Clique aqui e saiba mais sobre essa possibilidade.

Esses arquivos podem ser encontrados na pasta ‘Bibliotecas‘ no local onde foi instalado o RSClass – Gerador de Classes.

Utilizando a biblioteca assima não precisaremos escrever manualmente um DAO para cada tabela do banco. Podemos utilizar o RSClass para gerar os arquivos necessários. E vamos fazer isso agora. Na página inicial do post disponibilizei informações sobre onde baixar o RSClass. No post anterior fizemos a configuração do projeto e geramos os arquivos de mapeamento (.cs e .hbm.xml). Neste post vamos repetir o processo utilizando outra opção Gerar -> .DAO para gerar os arquivos de acesso a dados do sistema. Não será necessário refazer as configurações já que o RSClass guarda essas informações.

Gerando as interfaces e os DAO´s

Abra o RSClass e acesse a opção Gerar -> .DAO, marque a opção “Todas“; deixe as outras como estão. No nosso caso ficou assim:

rsclass_gerar_dao

Clique em ‘Gerar‘. Uma confirmação de localização será solicitada. Confirme e aguarde. Ao final voce receberá uma mensagem de sucesso da operação.

Vamos repetir o processo para gerar as interfaces. Acesse a opção no menu Gerar->.Interface->.DAO. Marque a opção ‘Todas’ e clique em gerar. Confirme a localização e aguarde a informação de operação realizada com sucesso.

Ufa! Os arquivos foram gerados. Agora vamos ao Visual Studio.

No Visual Studio

Com os arquivos gerados nas suas respectivas pastas precisamos agora inclui-los em seus projetos. O Visual Studio precisa reconhece-los como parte do projeto. Os passos a seguir devem ser efetuados em cada projeto do Visual Studio, no local onde os arquivos foram gerados.

  1. Selecione o projeto. Se os arquivos gerados não tiverem aparecendo clique no botão “Show all Files“. Depois selecione os arquivos, clique em qualquer dos arquivos com o botão direito do mouse e selecione a opção “Include In Project“.

Chegou a hora de utilizar a nossa biblioteca. Voce terá que adicionar as bibliotecas que voce baixou aos projetos.

  1. Projeto AgendaTelefonica.DAO: Clicando com o botão direito do mouse sobre o projeto selecione “Add Reference…“. Selecione a aba Browse e localize os arquivos Regisoft.Camadas.dll, Regisoft.dll e Regisoft.Camadas.Interface.dll na pasta ‘Bibliotecas’ no local o RSClass foi instalado. Selecione-as e clique em Ok.
  2. Proejto AgendaTelefonica.Interface: Clicando com o botão direito do mouse sobre o projeto selecione “Add Reference…“. Selecione a aba Browse e localize as bibliotecas Regisoft.dll e Regisoft.Camadas.Interface.dll (não inclua neste projeto Regisoft.Camadas.dll) no mesmo local do item anterior. Selecione-as e clique em Ok.

Se tudo foi feito como indicado o Solution Explorer estará como abaixo quando apresentar os projetos AgendaTelefonica.DAO e AgendaTelefonica.Interface.

Tecle Ctrl+F5 para montar o projeto. Se nenhum erro ocorrer voce concluio com sucesso essa etapa. No máximo, voce receberá uma mensagem informando que não há nenhum projeto que possa ser executado.

Vamos agora analisar os arquivos gerados.

  1. Abra primeiro o arquivo CidadeDAO.cs. Veja que não existe nada de extraordinário nele. Apenas 03 construtores diferentes na classe e um método que sugere a listagem de cidades pela UF. O mais importante é a definição da classe que herda de uma BaseDAO<Cidade,long> e uma interface ICidadeDAO. A BaseDAO é a classe que implementa as funcionalidades de persistências que já estão prontas para serem usadas. Como é uma classe genérica estamos usando <Cidade,long> que diz que o DTO a que esta classe se refere é ‘CIDADE’ e diz também que possui um campo chave primária do tipo ‘long’. É provável que precisemos de algumas novas funcionalidades na classe CidadeDAO.cs mas iremos adiciona-la depois. O principal (inclusão, exclusão, alteração, seleções de dados, transações, ect.) já está disponível pela herança. Abra também a classe ICidadeDAO.cs e veja que lá também não existe nada de mais. Apenas as herança de outra interface genérica e a assinatura de um método presente na classe CidadeDAO.
  2. Abra agora o arquivo DAOFactory.cs. Este será o arquivo por onde as regras de negócio farão acesso aos DAO´s. Voce entenderá isso melhor quando trabalharmos na geração dos BO´s. Veja que também possui uma inteface na sua declaração. Veja que seu construtor possui maneiras para acessar os DAO´s: com ou se servidor remoto. É possível planejar este sistema paraexecutar DAO´s e banco de dados numa máquina, regras de negócio em outra e servidor web em outra. Mas isso não faz parte do escopo do nosso projeto. Quem desejar conhecer mais sobre este assunto aguarde post posteriores ou registre algum comentário. Por hora voce deve entender que os DAO´s permitem flexibilidade de acesso graças a sua estrutura e o factory dos DAO´s sabe disso, permitindo que o programador escolha a forma de acesso que deseja trabalhar. Mas abaixo no arquivo voce vê exatamente os construtores dos DAO´s sendo chamados de acordo com aqueles construtores que mostramos no item 1, na classe CidadeDAO.cs que usamos como exemplo. O mais importante na nossa arquitetura é saber que os chamados aos DAO´s serão feitos através deste Factory (um padrão de projeto).

Estude bem este processo e os arquivos gerados. No próximo post vamos gerar os BO´s com suas interfaces. O procedimento é similar ao utilizado na geração dos DAO´s e suas interfaces. Estamos abertos a dúvidas e sugestões.

Se voce gostou e deseja ter os fontes dessas bibliotecas clique aqui. Conheça uma forma de adquirir ajundando a manter nossas pesquisas.

Outra coisa: Acesse http://tutorialagendatelefonica.googlecode.com para baixar o projeto gerado nessa etapa.

Até o próximo.

Visual Studio + NHibernate: Construindo aplicações em camadas – (cont. III)

No post anterior criamos o ambiente da aplicação no Visual Studio. Criamos os sub-projetos e definimos as hierarquias de acesso que caracteriza o desenvolvimento em camadas.

Neste post iniciaremos a codificação do nosso projeto Agenda Telefônica On-Line. O primeiro projeto que iremos codificar é o AgendaTelefonica.OR. Este projeto (ou esta biblioteca) será formado pelas classes que farão o papel de transferência de dados (DTO) entre as camadas. Essas classes ou os objetos irão trafegar livremente entre as camadas levando e trazendo informações. Já discutimos isso no post anterior. Neste projeto também dever haver os arquivos de mapeamento do Hibernate. As classe que vamos criar são as nossas ferramentas de trabalho. Os arquivos de mapeamento são as ferramenta de trabalho de Hibernate. Para cada classe criada deve existir um arquivo .hbm.xml correspondente. Este arquivo possui regras para mapeamento da classe com o banco de dados (not-null, FK, PK, FK, tipos e tamanho dos campos, etc.). Na prática, os arquivos .hbm.xml representam exatamente os campos das tabelas do banco de dados com seus respectivos tipos e relacionamentos. As classes também são uma retratação deste mapeamento.

Para cada tabela do banco deve existir:

  1. Um arquivo .hbm.xml que corresponde ao mapeamento relacional do Hibernate com a tabela do banco;
  2. Um arquivo .cs (poderia ser em outra linguagem) da classe que também corresponde a tabela do banco de dados.

Por isso que eu chamo (eu e todo mundo que usa Hibernate) esse projeto de AgendaTelefonica.OR. O OR significa Objeto/Relacional. Como ainda não existe uma banco popularmente conhecido orientado a objeto, o Hibernate faz esse relacionamento pra nós. Ele transforma o paradigma relacional do banco de dados em orientado a objeto pra faciliar o desenvolvimento das aplicações. Tudo que nós faremos durante o desenvolvimento em orientação a objeto, será transformado pelo Hibernate em paradigma relacional (SQL) que é o que o banco efetivamente entende.

Então vamos criar os dois arquivos para cada tabela da nossa aplicação e inserí-lo no Visual Studio. Como escrever esses arquivos é uma tarefa repetitiva e metódica, é interessante que se trabalhe com gerador de código. Vamos utilizar o RSClass para gerar os arquivos. Este programa foi indicado para instalação no primeiro post deste tutorial.

A utilização do RSClass é bem simples. Ao executar o programa pela primeira vez deve-se configurar o ambiente. Acesse o menu Arquivo->Configuração e efetue as modificações necessárias. No meu caso ficou assim:

rsclass_config

A pasta destino deve ser a pasta da solução criada pelo Visual Studio no post anterior. Note também que o no campo projeto o nome foi informado compatível com as camadas geradas no post anterior.

Feita as configurações, ainda no RSClass acesse o menu Gerar -> .OR, marque a opção Todas e clique no botão Gerar. Na caixa de diálogo confirme o destino informado pelo sistema e aguarde a informação de que tudo foi gerado com sucesso. Se o destino não tiver correto cancele a operação e reconfigure tudo na tela de configuração do programa.

Se tudo foi gerado corretamente, quando abrir no Visual Studio a nossa solução, vai encontrar algo assim (selecione o projeto AgendaTelefonica.OR, localize no Solution Explorer o botão “Show All Files” e clique nele):

Finalmente temos mais duas configurações a fazer:

  1. Incluir ou anexar ao projeto AgendaTelefonica.OR os oito arquivos gerados;
  2. Alterar as propriedades “Buid Action” dos arquivos .hbm.xml.

Vamos fazer isso. Selecione os oito arquivos e, com eles selecionados, clique em algum com o botão direito do mouse e clique na opção “Include in project“. Depois selecione apenas os arquivos com .hbm.xml e, com eles selecionados, clique em algum deles com o botão direito do mouse e clique na opção “Properties”. Quando a aba de propriedades aparecer, mude o “Build Action” para “Embedded Resource“.
Essa mudança fará com que os arquivos do hibernate seja embutidos na bliblioteca da classe durante a compilação. É comum esquecer de realizar este processo. Na execução da aplicação, o Hibernate vai gerar uma exceção (um erro) que muitas vezes não é tão fácil de identifcar que o problema é não ter alterado a propriedade Build Action dos .hbm.xml. Por isso FIQUE ATENTO A ESTE PASSO. Se tudo foi feito corretamente o Solution Explorer estará assim:

E a propriedade Build Action de todos os .hbm.xml estarão assim:

Mais uma coisa: vamos adicionar uma outra biblioteca ao projeto AgendaTelefonica.OR. Clique com botão direito do mouse sobre o projeto e selecione “Add Reference…”. Localize o arquivo Regisoft.dll que está em ‘Bibliotecas‘ na pasta de instalação do RSClass e adicione ao projeto.

Pronto. Vencemos mais esta etapa. Já temos nossa blibioteca com as classes e mapeamento para Hibernate. Inclusive as classes dessa biblioteca irão servir como objetos de transferência de dados (DTO). Tente compilar/executar a solução. Não deve dar nenhum erro,  no máximo um um aviso informando que não há nenhum projeto que possa ser executado. Normal… Afinal são apenas Class Library.

Também é interessante que voce abra os arquivos .cs e os arquivos .hbm.xml gerados e tente identificar os componentes comparando com as tabelas do banco de dados. Se voce desejar se aprofundar neste conhecimento, abaixo, tem um link para uma excelente apostila sobre o entendimento do Hibernate e suas configurações nos arquivos de mapeamento. Vale apena olhar. Fala sobre o Hibernate do Java, mas a compreensão é a mesma para o NHibernate do .NET.

Clique aqui e veja a apostila.

No próximo post vamos trabalhar com o projeto AgendaTelefonica.DAO e AgendaTelefonica.Interface, na pasta DAO. Vamos criar os DAO´s e as interfaces para os mesmos.

Até lá.

Visual Studio + NHibernate: Construindo aplicações em camadas – (cont. II)

No post, anterior foram definidos o ambiente de trabalho e requisitos do Sistema Agenda Telefônica on-line. Agora vamos definir o ambiente de desenvolvimento da aplicação no Visual Studio. Lembre-se que será definido em camadas. É comum definir um único Project no Visual Studio e criar pastas dentro deste projeto para definir os DAO´s, BO´s e DTO´s, etc. Faremos um pouco diferente. Vamos criar uma Solution e, nela, adicionaremos projetos que irão acomodar os objetos das camadas.

Criar a solução…

Agora vamos adicionar projetos a nossa solução. Vamos adicionar inicialmente 4 projetos:

  1. AgendaTelefonica.OR – Para acomodar os objetos de transferência de dados (DTO´s). Neste projeto iremos adicionar as classe e os arquivos de mapeamento do NHibernate com o banco de dados;
  2. AgendaTelefonica.Interface – Para acomodar as classes de interface dos DAO´s e dos BO´s. Internamente haverá duas pastas, DAO e BO, que acomodará as interfaces respectivas.
  3. AgenteTelefonica.DAO – Para acomodar os DAO´s;
  4. AgendaTelefonica.BO – Para acomodar os objetos de negócio.

Falta ainda adicionar um último projeto qué é exatamente a aplicação web; o site por onde o usuário irá acessar o nosso sistema. Mas vamos deixar isso para o final.

Adicionando os projetos…

Após ter criado este projeto, crie duas pastas: DAO e BO. Até o momento o Solution Explorer deve estar assim:

Ao final da criação dos projetos o Solution Explorer deve estar assim:

Antes do próximo passo precisamos lembrar alguns conceitos.

  1. A biblioteca AgendaTelefonica.OR receberá os arquivos de mapeamento de Objetos Relacionais do NHibernate. Funcionará como DTO´s, ou seja, este objetos trafegarão livremente entre as camadas levando e trazendo informações. Portanto todas as outras bibliotecas, inclusive o site que ainda vamos criar, precisam “ver” essa biblioteca.
  2. A biblioteca de interface – AgendaTelefonica.Interface – será utilizada na declaração dos DAO´s e dos BO´s. Inclusive essas intefaces tem uma utilidade importante que é desacoplar as camadas no sistema e ajudar na escalabilidade. Inclusive, instanciamento dos objetos das camadas deve ser através das suas intefaces. Isso garante o desacoplamento. Logo todas a camada de acesso a dados, negócio e a aplicação devem “ver” esta biblioteca.
  3. Uma hierarquia de acesso precisa ser obedecida na construção em camadas. A aplicação web ou desktop faz requisições somente à camada de negócio; representada pela biblioteca AgendaTelefonica.BO. As regras de negócios fazem requisições soment à camada de acesso a dados (AgendaTelefonica.DAO) que, por sua vez, acessa o banco de dados através de uma camada extra chamada Camada de Persistência que, no nosso sistemas, será responsabilidade do NHibernate. NUNCA e NUNCA MESMO, em camadas, essa hierarquia de acesso pode ser desobedecida. A camada superior faz requisições à cada imediatamente inferior e, esta, apenas responde as requisições. Em outras palavras, a camada superior executa um método de um objeto presente na camada inferior para realizar alguma operação e/ou receber alguma informação. Nunca ao contrário. Se em algum momento o DAO, por exemplo, fizer uma chamada ao BO, isso pode ser tudo. Menos arquitetura em camada. Ou se, a aplicação web fizer uma chamada diretamente ao DAO pulando o BO, ou se o BO fizer um acesso ao banco de dados diretamente pulando o DAO, ou mesmo, se o DAO fizer chamada diretamente ao banco pulando a camada de persistência, em qualquer uma das situações a aplicação perde a característica do que nos chamamos ARQUITETURA EM CAMADAS.

No Visual Studio é possível garantir as hierarquia de camadas. Teremos que adicionar a referência de um projeto em outro segundo o que foi discutido nos itens acima:

  1. Em AgendaTelefonica.Interface adicionamos referência a AgendaTelefonica.OR;
  2. Em AgendaTelefonica.DAO adicionamos referência a AgendaTelefonica.OR e AgendaTelefonica.Interface;
  3. Em AgendaTelefonica.BO Adicionamos referência a AgendaTelefonica.OR, AgendaTelefonica.Interface e AgendaTelefonica.DAO;

Lembre-se: OR e Interface estão em todas pelas suas características: Transferência de dados para OR e desacoplamento para Interface.

Como nosso DAO utilizará o NHibernate voce deve adicionar em AgendaTelefonica.DAO referrência ao NHibernate também (localize a instalação que voce fez do RSClass – Gerador de Classes). Detalhe: adicione somente no DAO.

Para adicionar uma referência a um projeto voce deve clicar no botão direto do mouse sobre o projeto e selecionar Add Reference… Selecione a aba Projects e faça as adições ao projeto atualmente selecionado.

Depois de ter feito isso para cada projeto, adicione referência do NHibernate a AgendaTelefonica.DAO. Clique no projeto com o botão direito, Selecione Add Reference…, selecione a aba Browse e localize o arquivo NHibernate.dll na pasta de ‘Bibliotecas’ localizada na pasta de instalação do programa RSCLass – Gerador de Classes (esta instalação deve ter sido feita no primeiro post deste tutorial).

Como todas as referências adicionadas o Solution Explorer deve se apresentar assim:

Pronto. Mais uma etapa cumprida. Nosso ambiente está pronto. Vimos como criar uma aplicação em camadas no Visual Studio respeitando a hierarquia. Registrem comentários e dúvidas.

Na página http://tutorialagendatelefonica.googlecode.com voce pode encontrar os arquivos deste tutorial gerados até aqui (PARTE II). No próximo post iremos começar a criar os arquivos de cada projeto, iniciando pelo OR.

Até o próximo.

Visual Studio + NHibernate: Construindo aplicações em camadas

Devido a grande quantidade de dúvidas recebidas, decidi escrever um pequeno tutorial de como construir uma aplicação em camadas utilizando o NHibernate no Visual Studio. Vamos construir uma aplicação completa utilizando estes recursos e o conceito de camadas. Tentaremos fazer uso de alguns padrões de projeto para enriquecer nosso tutorial.

Não vamos tratar de conceitos. Iremos apenas utilizar as ferramentas na aplicação dos mesmos. Na internet existe uma vasto conteúdo sobre os assuntos aqui relacionados. Também é importante que o leitor tenha conhecimento da utilização do Visual Studio já que não iremos explicar seu funcionamento detalhamente no desenvolvimento da nossa aplicação.

Então vamos lá.

Montagem de Ambiente

Inicialmente vamos definir as configurações e requisitos para nosso trabalho:

  1. Ambiente de desenvolvimento: Visual Studio 2008 SP1 profissional com suporte a C#.
  2. Banco de dados: Firebird 2.1.3.18185.
  3. Ferramenta para administração do banco de dados: FlameRobin v0.9.3.1870 .
  4. Framework de persistência:  NHibernate v2.1.0 GA.
  5. RSCLass – Gerador de Classes. Baixe e instale esse programa. Ele irá gerar a maioria dos arquivos que iremos utilizar em nossa aplicação.

Com tudo instalado e funcioando corretamente já podemos iniciar os trabalhos.

O Problema

Vamos imaginar o seguinte problema: a secretária do diretor não quer mais ser encomodada pelo resto da empresa, que toda hora liga para ela perguntando dados e telefones de clientes e pessoas em outras filiais. Ela explicou a situação para o diretor e ele concordou. O diretor então chamou o gerente de TI e determinou que ele resolvesse o problema.

Especificação de Requisitos

Após análise e discursão, chegou-se a conclusão que deveria existir na empresa uma Agenda Telefônica na intranet, para que todos possam acessar, cadastrar, alterar, consultar e listar contatos. Mas, para ter acesso a agenda, cada usuário precisaria de uma senha. Uma regra importante é que somente o usuário que incluio o contato pode ter a permissão para excluí-lo. Porém, todos podem alterar, listar e consultar quaquer contato registrado. Se um contato for definido como confidêncial, somente o usuário que cadastrou teria o direito a visualizar, modificar, consultar ou excluir. Se um usuário for excluído, seus contatos passam a ser de domínio público, ou seja, todos ganham o direito de gerenciar os contatos do usuário excluído.

Vamos construir este sistema para WEB e em camadas.

A Modelagem

Fiz um pequeno diagrama do módelo conceitual do sistema.

Como pode ser visto o sistema terá 4 classes: Usuario, Contato, Cidade e UF. UF compõe Cidade que, por sua vez, compõe Contato. Usuário gerencia o contato.

Fiz também o diagrama de entidades relacionais.

Todos os arquivos necessários para execução do tutorial podem ser encontrados em http://tutorialagendatelefonica.googlecode.com. Baixe o script do banco que foi gerado para o Firebird. Utilize o FlameRobim para criar o banco de dados e rodar o script ou, então, utilize um banco de dados e ferramenta administrativa de sua preferência.

OK! O projeto foi definido e o banco está pronto. No próximo post utilizaremos o Visual Studio para definir a aplicação. Fique a vontade para comentar e registrar suas dúvidas até aqui.

Padronização de nomeclatura de banco de dados

Eis uma coisa complicada. Cada programador, analista ou DBA tem uma forma de entender e montar uma estrutura de banco de dados.

Lembro-me do tempo do CLIPPER onde os arquivos DBF´s e NTX´s eram bem limitados. Tinha um esquema comumente chamado de 8.3 para nome de tabelas e quantidade limitada de caracteres para nome de campos. Tinhamos que fazer verdadeiros milagres no momento de dar nome as campos das tabelas. Haja abreviações. Era preciso definir padrões para as abreviações, bem documentados, para que outro programador pudesse entender, ou mesmo, o próprio desenvolvedor entendesse o que havia feito na hora de dar manutenção no sistema.

Com o avanço tecnológico, muita coisa mudou nessa área. Por exemplo, a evolução dos sistemas operacionais nos permite indentificar com mais clareza os arquivos. De igual forma, os bancos de dados relacionais. Houve um aumento no tamanho permitido para nome de tabelas, campos, chaves, etc.

Porém, com todo esse avanço, vejo que muita gente quer preservar algumas características legadas para dar nome às entidades relacionais do banco de dados. Por exemplo: um campo da tabela que servirá pra guardar endereço, há quem utilize END para nome do campo; um campo utilizado pra guardar a razão social, ha quem utilize RAZ_SOC para nomear o campo. Eu pergunto: PRA QUE TANTA ABREVIAÇÃO DE NOMES, HOJE EM DIA? Se o banco permite, porque não utilizar os nomes sem abreviações desnecessárias?! As justificativas apresentadas são as mais variadas. Mas não ouvi nenhuma que seja realmente convicente. Inclusive, se for uma prática do leitor usar essaS abreviaturas nos bancos de dados atuais, peço que registre um comentário explicando o seu motivo pra abreviar.

Mas não é só essa questão. Por exemplo, alguns analistas tem o costume de identificar os tipos de entidade no nome da entidade. Por exemplo: A tabela de usuários será nomada assim: TB_USUARIO. Uma vez eu vi uma situação que achei um excesso. Uma tabela com o seguinte nome de campo: TB_USUARIO_LOGIN, ou seja, o nome da tabala compondo o nome do campo. Essa prática é pouco indicada pra quem trabalha com orientação a objeto. Quem trabalha mapeamento O/R (como no Hibernate, por exemplo) terá um trabalho dobrado pra reduzir estes nomes; para adequar os nomes das tabelas à definição das classes persistentes.

Mas a realidade é essa: cada um com sua forma de pensar. Nas próximas linhas vou definir a minha. Como eu utilizo geradores de código apartir de definições de banco, é importante adotar um comportamento padrão. Vamos lá.

Definições Gerais

  1. Evitar abreviações. O nome completo deve ser preferido.
  2. Só utilizar letras maiúsculas.
  3. O nome das entidades de banco deve ser no sigular.
  4. Procurar utilizar nomes que identifiquem sua utilidade e aplicação.
  5. Para nomes compostos, separar com underline, por exemplo: RAZAO_SOCIAL.
  6. Evitar usar o nome da entidade em seus componentes internos, por exemplo: Se o nome da tabela for PACIENTE, o campo para preenchimento com o nome do paciente será NOME e não NOME_PACIENTE.

Tabelas

Para objetos relacionados com tabelas (chave primaria, chave estrangeira, campos, indices, etc.) vamos adotar o seguinte comportamento:

Chave Primaria

  1. Não usar chave primária composta.
  2. Deve ser sempre o primeiro campo na tabela e ser formado por “ID_NOME_DA_TABELA”. Para tabela PACIENTE, por exemplo, o champo de chave primária será ID_PACIENTE.
  3. O tipo do campo deve ser do tipo numérico mais abrangente possível ( numeric[18,0], bigint ), auto-incremental, com sequence ou generator, se necessário. Não use triggers para auto-incrementar o campo.

índices

  1. Deve ser criado sempre; de acordo com as necessidades de ajuste do banco. Normalmente os campos utilizados para ordenação e filtro nas querys precisam de índices.
  2. Para os campos que poderiam ter sido escolhidos para chave primária composta, construir o indice com a combinação dos campos utilizando índices marcados como únicos (unique).
  3. Deve ser formado por IX_NOME_DA_TABELAn. O ‘n’ no final é apenas um numero sequencial (1,2,3…) para diferenciar os nomes dos índices. Por exemplo: a tabela PACIENTE terá dois índices: IX_PACIENTE1 E IX_PACIENTE2. O primeiro índice pode ter o “1″ opcionalmente. O outros indices (apartir de “2″) são sobrigatórios.

Chaves estrangeiras

  1. Na tabela, o nome do campo deve ser igual ao campo chave primária da tabela a que corresponde.
  2. Indentificado assim: FK_NOME_DA_TABELA_NOME_DA_TABELA_ESTRANGEIRA. Por exemplo: a tabela PACIENTE possui uma chave estrangeira para tabela SEXO. O nome do campo na tabela PACIENTE deve ser ID_SEXO e o nome da chave estrangerira será FK_PACIENTE_SEXO.

Restrições (constraint)

  1. Opcional. Eu evito utilizar. Prefiro utilizar na camada de negócio.

Tipos

  1. Respeite o tipo de dado para o campo. Campo data para guardar datas, numéricos para guardar números, etc.
  2. Alguns bancos disponibilizam tipos comum com quantidade de bytes reduzidas. Por exemplo: para campo numérico existe: int, smallint, tynint, etc. Procure evitar as variações. Prefira os tipos que são comuns a todos os tipos de bancos. Use os tipos abaixo. Eles costumam ter tamanho bem definido e nome de tipos comuns a todos os bancos.
  • Numéricos: int ou integer
  • Data: DateTime ou TIMESTAMP
  • String: varchar
  • Boolean: smallint ou bit
  • Campos bynários ou longos: BLOB

SEQUENCE ou GENERATOR

  1. Deve ser criada da seguinte forma: GEN_NOME_DA_TABELA_ID. Para a tabela PACIENTE crie um sequence ou generator GEN_PACIENTE_ID.

Visões

  1. O nome da view deve ser V$NOME_VIEW ou VNOME_VIEW. Ex: V$PACIENTE_INTERNADO ou VPACIENTE_INTERNADO

Procedures, Functions, Triggers…

Eu evito terminantemente utilizar objetos que possam exigir reescrita caso seja necessário mudar de banco de dados, exceto as views, claro. Inclusive eu escrevi um post sobre “Independência de Banco de Dados”. Leia mais…

É isso. Espero ter ajudado. Quem tiver alguma maneira diferente de entender ou enxergar este assunto, por favor, não deixe de registrar um comentário ou me enviar por email. Desde já obrigado.

Blz!

Google Maps para ASP.NET

Achei um control para ASP.NET que permite inserir facilmente o Google Maps na página. Inclusive, pode-se também inclui-lo no Toolbox do Visual Studio. Tudo muito simples (quem tiver dúvida sobre essa inclusão no VS deixe um comentário que eu respondo).

Mas, para utiliza-lo, é preciso ir em Google Maps API para obter uma chave. O control possui uma propriedade (Key) onde a chave obtida deve ser inserida.

Clique aqui para baixar o componente diretamente da página do seu criador.

Pronto. Incluio na Toolbox, arrastou o control, colou no webform e inseriu a chave? Tem um pequeno código que voce deve inserir na sua página para que o Google Maps possa localizar as coordenadas desejadas.

Adicione esta linha as Using’s:
using Subgurim.Controles;

O código é este:
protected void Page_Load(object sender, EventArgs e)
{

double latitude=10, longitude=10; // indica as coordenadas para o ponto do mapa


GMap1.addControl(new GControl(GControl.preBuilt.GOverviewMapControl));
GMap1.addControl(new GControl(GControl.preBuilt.LargeMapControl));
GMarker marker = new GMarker(new GLatLng(latitude,longitude));
GInfoWindow window = new GInfoWindow(marker, “<strong>Nome do Local</strong>”, true);
GMap1.addInfoWindow(window);
}

Encontrei, também, um outro blog que indica um outro componente similar: http://angelobestetti.blogspot.com. Baixei e instalei. É bem parecido com o outro. Não testei mas acho que ambos são úteis.

Blz!!!!

Editor de texto na web

Estava a procura de um componente para edição de textos na web. Achei o FCKEditor. Muito bom mesmo. Permite uma infinidade de configurações. Posso destacar algumas:

  1. É possível adaptar a barra de ferramentas adicionando ou excluindo botões de acordo com a necessidade.
  2. Área compartilhada para armazenamento das imagens utilizadas pelos usuários.
  3. Impressão do documento diretamente do editor.
  4. Vários recursos para edição de texto.

Utilizei o componente para confecção de laudos médicos de exames. Dessa forma posso armazenar formatação padrão para os laudos no banco de dados e os profissionais de saúde pode editar o laudo do paciente como se tivesse em um programa desktop para edição de texto.

Visite FCKEditor.net.

A instalação é bem simples. Primeiro, o editor propriamente dito deve ser baixado e descompactado, por exemplo, no site onde será utilizado. Depois o componente .net deve ser baixado, descompactado em algum lugar e depois o assembly (.dll) pode ser incluído no ToolBox do Visual Studio. Possui versão para VS 2003, VS 2005 ou superior.

Alguns arquivos JavaScript podem ser modificados para configuração do editor. O arquivo principal é o fckconfig.js. Neste arquivo voce pode configurar, entre outras, barra de ferramenta do editor, ambiente de implantação do sistema, linguagem do editor, etc.

Não posso deixar de sugerir uma aplicação que desenvolvi que utiliza o FCK Editor. A aplicação é EDWS – Sistema de Gerenciamento de Conteúdo. Esta aplicação permite incluir, alterar e excluir páginas de um site. Tudo dinamicamente. Através do FCK Editor o proprietário do site pode incluir imagens, textos, links, etc. em tempo de execução, como se estivesse em um editor de páginas HTML. As páginas são armazenadas em arquivos XML dispensando o uso de banco de dados. Saiba mais em EDWS Blog.

Muito bom!!!

Classe DAO genérica com Hibernate – (cont. II)

Num post anterior, fiz algumas considerações sobre funcionalidades de uma classe DAO genérica. Destaquei uma configuração mínima em métodos que uma Classe DAO pode ter para ser útil. Leia mais.

Agora irei descrever algumas novas funcionalidades (novos métodos), que acrescentei a minha classe DAO que pode ser de grande ajuda para todos. Vejamos primeiro o interface original com os acréscimos que fiz:


/* T é o tipo da classe que a DAO irá gerenciar e ID é o tipo do campo chave primária. Não utilize chave composta nem chave com dados naturais, ou seja, dados com significado, por exemplo, RG, CPF, etc. O ideal é utilizar um campo numérico auto-incrementável na chave primária.*/

public interface IBaseDAO<T, ID> : IDisposable
{
void BeginTransaction(); //Inicia transação
void CommitTransaction(); //Grava transação
void RollbackTransaction(); //Desfaz transação
T SelecionarPorId(ID id); // Seleciona um registro pelo ID
T Inserir(T obj);
T Alterar(T obj);
void Excluir(T obj);
IList<T> Listar(string ordem); //listar ordenado por campo
ICriteria getCriteria();
ISession getSession();
T Atualiza(T obj);
void Excluir(IList<T> lst);
void Incluir(IList<T> lst);
void Alterar(IList<T> lst);
bool EmUso<U>(string join, string propertyName, ID objectValue);
IList CreateQuery(string hql);
IList<U> CreateQuery<U>(string hql);
T UniqueResult(string hql);
U UniqueResult<U>(string hql);
T SelecionarPor(string propertyName, object value);
void ValidaNotNull(T obj);
DataTable ToDataTable(IList<T> lst);
string InsertSQL(T objPersistente);
string UpdateSQL(T objPersistente);
string DeleteSQL(T objPersistente);

}


  • ValidaNotNull – Este método recebe um objeto hibernate (transiente ou persistente) e faz uma validação NOT NULL. Nos arquivos .hbm.xml constam as configurações das propriedades. Este método verifica se os campos ou propriedades não nulos do objeto passado como parâmetro de entrada estão efetivamente com conteúdo, ou seja, não nulos. Eu simplesmente incluo no início do método de inserção e/ou alteração no objeto de negócio uma linha: ValidaNotNull(paciente), por exemplo. O método verifica se as propriedades not-null possuem conteúdo. Se alguma propriedade for NULL e não deveria ser o método retorna uma excessão informando os campos que deve conter algum valor.
  • ToDataTable – Este método recebe uma lista e transforma num DataTable. Ele constroi uma tabela onde as colunas serão o nome das propriedades do tipo de objeto da lista. Para as propriedades <many-to-one> ele cria também colunas para acomodar os valores das propriedades do relacionamento. O título da coluna fica algo assim: Paciente.Cidadao.Sexo.Descricao e o conteúdo do campo será a descrição do sexo do cidadão paciente. Se nos <many-to-one> tiver outros <many-to-one> novas colunas vão sendo criadas até chegar nas propriedades que não são relacionamentos, seguindo a mesma idéia citada acima para nome de colunas. E as linhas serão exatamente o conteúdo dos campos nas propriedades de acordo com título da coluna.
  • InsertSQL – Este método recebe um objeto persistente como parâmetro e retorna o SQL-ANSI correpondente para inserção do dado.
  • UpdateSQL – Este método recebe um objeto persistente como parâmetro e retorna o SQL-ANSI para alteração da linha correspondente ao objeto persistente no banco de acordo com a chave primária (não composta).
  • DeleteSQL – Este método recebe um objeto persistente como parâmetro e retorna o SQL-ANSI para exclusão da linha correspondente ao objeto persistente no banco de acordo com sua chave primária (não composta).

Estes três últimos métodos são interessante pra quem desejar fazer replicação assíncrona de dados baseado em log. Estes DML´s são guardados numa tabela de log´s, inclusive o início e fim de cada transação, para que um módulo replicador possa ler cada linha e executá-la no banco slave ou banco cópia.

A implementação que fiz para estes métodos depende da classe NHibernate.CFG.Configuration que configura o ambiente hibernate. Essa instância de configuração deve estar visível internamente em cada um dos métodos assima descritos. Dessa forma pode-se ler os arquivos hbm.xml para atingir os objetivos.

Se alguém tiver mais sugestões de métodos para nossa classe DAO pode postar aqui.

Valeu!!!!


Calendário

Junho 2008
D S T Q Q S S
« Mar   Jul »
1234567
891011121314
15161718192021
22232425262728
2930  

Desde (04/11/07)

  • 43,992 visitas