Apêndice 2: Relatórios em .NET com NHibernate

Quem utiliza sistemas de informações sabe da importância dos relatórios. Eles são tão importantes quanto o próprio banco de dados. Listagens, gráficos, resumos, sumários, formulários são alguns exemplos de resultados que essas ferramentas devem ser capazes de fornecer. Claro que dada tipo de resultado será aplicado em um contexto. Cada sistema precisa emitir relatórios de acordo com a necessidade do trabalho onde for utilizado. Por exemplo, os gráficos são normalmente utilizados para avaliação e gestão. As listagens são utilizadas para buscas, levantamentos, etc. O fato é que relatórios são de vital importância para quem utiliza algum sistema de gerenciamento de dados.

Por outro lado, os desenvolvedores de sistemas sabem da dificuldade de se construir um relatório. Isso sem falar das alterações que possam surgir posteriormente. Todos procuram alguma ferramenta que possa minimizar o desgaste natural causado pelo processo de construção e manutenção de relatórios. A situação tende a se agravar quando falamos de relatórios para sistemas web. Isso por que os navegadores trabalham com HTML. A situação natural é montar relatórios utilizando esta linguagem diretamente e isso não é tão trivial assim. Mesmo utilizando alguma outra linguagem que rode do lado do servidor o resultado final deve ser em HTML que é o que os navegadores são capazes de exibir. Para aumentar o poder desses navegadores alguns recursos podem ser utilizados: ActiveX, Plugins, Flash, Applets, etc. Essas e outras tecnologias, além de dar maior poder aos navegadores, aumentam a produtividade dos desenvolvedores já que podem utilizar ferramentas mais completas para gerar os relatórios que serão vistos nos navegadores.

Em .NET não seria diferente. Montar relatórios é um processo muito delicado. A pergunta é qual a melhor forma? Qual a melhor ferramenta? Resposta: EU NÃO SEI. Mas será que existe uma forma dita “melhor”?! Mas, como todo programador, eu também tenho a minha forma que pode não ser a melhor nem a mais ortodoxa. Mas é a minha forma e é com ela que tenho resolvido a maioria dos problemas. Vou compartilhar com voces.

A minha primeira experência em .NET foi quando eu tive que migrar um sistema do Delphi para o Visual Studio 2003. Neste sistema existe inúmeros relatórios. Inicialmente fiz as telas de usuário. Como o sistema em delphi utiliza as procedures de banco como regras de negócio não tive muitos problemas. Tive apenas que refazer as telas que iriam chamar as procedures. O problema começou na hora dos relatórios. Inicialmente tentei utilizar o Crystal Reports. Não me identifiquei com ele. Achei muito complicado e etc. A primeira solução que me veio a cabeça foi a seguinte: já que os relatórios estavam todos prontos em Delphi utilizando views e procedures do banco de dados decidi criar em Delphi um servidor de relatórios. O funcionamento era +ou- assim:

  1. Um programa executavel criado em delphi e instalado no servidor encapsulava todos os meus relatórios. Este programa tinha a capacidade de exportar relatórios em PDF para a pasta web da minha aplicação.
  2. Este programa era chamado de dentro da minha aplicação asp.net passando alguns parâmetros: id-relatorio, arq-pdf-saida, param-1, param-2, … , param-n. O id-relatório identificava o relatório que eu gostaria de imprimir. Os parêmetros, de 1 a n, eram passados de acordo com a necessidade da instrução SQL do relatório.
  3. O programa recebia estes parêmtros, conectava-se ao banco, extraia os dados do banco, montava o relatório e exportava para pdf em uma pasta com nome e path indicado pelo arq-pdf-saida.
  4. A aplicação aguardava o término do processo até um certo limite e redirecionava o browser para o arquivo pdf gerado. Com o Adobe Reader instalado o navegador baixava este pdf e exibia ao usuário.

Durante muito tempo este sistema funcionou assim. Principalmente por que eu não tinha muito tempo para refazer toda aplicação inclusive os relatórios em 100% .NET utilizando o Crystal.

Mas, novas versões deste sistema foram surgindo e com elas, a necessidade de utilizar uma forma 100% .NET de fazer relatórios. Fiz algumas buscas e achei algumas ferramentas muito interessantes:

  1. DevExpress
  2. Afalinasoft
  3. StimulSoft
  4. PerpetuumSoft
  5. (…)

Algumas eu testei e gostei. Todas são muito boas e integradas ao IDE do Visual Studio. Cada uma com suas características e diferenciais. Mas todas tem a principal limitação para o tipo de trabalho que eu faço: não são gratuitas. Porém nada impede de utilizar a versão demo convivendo com algumas situações. Uma coloca o nome DEMO no meio de cada página impressa. Outra limita o número de páginas impressas. Outra coloca uma pequena propaganda no final da página. Enfim…. Pra mim era inviável.

Há também quem prefira fazer relatórios em HTML para exibir diretamente no navegador. Separei também um link para esses programadores: http://www.webly.com.br/tutorial/net/8861/aspnet-gerar-relatorio-em-html.htm.

Foi quando eu conheci o ReportViewer. Estudei um pouco sobre ele. Dê uma olhada nos endereços abaixo e conheça também um pouco mais:

  1. http://www.macoratti.net/aspn_grv.htm
  2. http://www.devmedia.com.br/articles/viewcomp.asp?comp=5371
  3. http://blog.adsystems.com.br/2009/04/10/tutorial-c-relatorios-master-detail-com-reportviewer/
  4. http://www.macoratti.net/08/03/vbn5_rpv.htm
  5. http://www.macoratti.net/08/03/vb8_rpv2.htm
  6. http://csharpbrasil.com.br/2008/09/11/criando-relatorio-com-reportviewer-em-aspnet/

Não vou entrar em detalhes do funcionamento. Os links acima são bem explicativos. Mas duas novas questões surgem:

  1. Eu não gostaria de utilizar o visualizador padrão do ReportViewer. Gostaria de exportar os relatórios diretamente para pdf para utilizar o Adobe Reader como visualizador no prórprio navegador.
  2. Gostaria da utilizar o NHibernate como minha fonte de dados também. O natural é conectar o banco com algum DataSource. Gostaria que os dados viessem da minha camada de negócio (BO) e não conectando diretamente o banco. Principalmente pelo fato da independência de dados que já comentei e posts anteriores. Sem falar no fato de obedecer as regras da arquitetura em camadas.

Graças a Deus, consegui resolver os dois problemas. Não pretendo construir um tutorial para cada solução.Vou passar a idéia da solução. A implementação da proposta fica como exercício para o leitor. É necessário ter conhecimento intermediário de OOP, persistência com NHibernate, Visual Studio e arquitetura em camadas. Em posts atenteriores dou uma ajuda nessas questões. Vale a pena dar uma olhada.

Vamos ao que interessa.

  1. Os relatórios desenvolvidos com ReportViewer podem ter como fonte de dados os DataTables. Esses DataTables podem ser criados tanto em tempo de execução quanto em tempo de desenvolvimento. Para nossa proposta é legal criá-los em tempo de desenvolvimento. Isso irá facilitar a confecção do arquivo de relatório (.rdlc). Faça isso. Abra um projeto no VS e adicione um item DataSet. Neste DataSet adicione um DataTable. As colunas do DataTable serão os campos que vc irá imprimir. Adicione as colunas com seus respectivos nomes.
  2. Adicione um novo item ao seu projeto. Este item deve ser um Report (.rdlc). Agora voce deverá formatar o relatório de acordo com sua necessidade. Os links acima dão uma ideia de como trabalhar com a IDE. Uma coisa importante: as colunas do seu relatórios devem ser vindas do DataTable que voce criou no item anterior. Mas para que seja possível fazer essa associação voce deve vincular o relatório ao DataTable. No menu Report, selecione o DataSource. Na caixa suspenda selecione o DataTable que voce criou indicando-o como fonte de dados do relatório. A partir daí voce já pode adicionar colunas ao seu relatório.
  3. Talvez vc queria indicar algumas informações no cabeçalho do seu relatório, tais como: nome da empresa, período, setor, etc. Isso deverá ser passado ao relatório através de parâmetros. No menu Report->Report Parameters voce pode indicar todos os parêmetros que desejar e posicioná-los no cabeçalho do relatório.

Neste relatório voce pode definir: grupos, sumários, totais, gráficos, tabelas com números de linhas e colunas variáveis, etc. Consulte documentação do ReportViewer. Com um pouco de prática tudo vai parecer muito natural. No início eu támbem demorei um pouco a me familiarizar com o ambiente. Há quem diga que no ReportViewer não dá pra fazer relatórios muito complexos. Para os relatórios do dia a dia tenho tido ótimos resultados. Sem falar no fato: ReportViewer é uma solução gratuita. Qualquer relatório mais complexo que sua empresa precise, posivelmente tenha que meter a mão no bolso. 😉

Mas, continuando… A questão agora é o Nhibernate. Sem problemas! No seu DAO e/ou BO voce deve ter um método que retorne para a camada de apresentação os dados que prentende utilizar no relatório. Esses dados podem ser retornados de diversas formas: IList, IList<> ou o próprio DataTable, inclusive utilizando a estrutura definida no DataSet/DataTable do relatório. Não aconselho usar DataTable nas camadas BO e DAO para retornar dados. Surigo utilizar sempre IList<> nessas camadas e deixar pra conversão em DataTable na camada de apresentação utilizando algum foreach. (Já notou que eu uso C#, não é?) O DataTable destino será aquele mesmo que formatou o relatório do ReportViewer. Associe o DataTable o relatório, preencha os campos de parâmetros e mande exibir. Vc pode seguir um dos tutoriais que indico acima.

Mas se vc não quiser utilizar o visualizador padrão do ReportViewer? Eu sempre exporto o relatório para PDF e envio os bytes do arquivo diretamente para o STREAM de tela. No browser do cliente o Adobe Reader captura isso e abre no browser como arquivo PDF. Não há necessidade de gerar arquivo em disco como eu fazia no início.

Mas como fazer esta exportação! Vou dar duas sugestões. A primeira é aprender como se faz consultando os seguintes links: Link 1 e Link 2. A outra opção é “use o que tá pronto”. Na página de Sistemas c/ Fontes deste blog eu disponibilizo uma aplicação que faz exatamente as coisas que eu descrevi aqui. A aplicação é Contas a Pagar on-line. Nele voce pode encontrar os arquivos .rdlc criados, o DataSet com os DataTables criados e o método de exportação em PDF em funcionamento. Há métodos para exportão para Excel e PDF, em vetor de bytes (o que possibilita o envio do resultado diretamente para o ‘stream’ de tela) ou arquivo. Fica a sua escolha. Inclusive mostra como passar parâmetros para o relatório. Esse parâmetros podem ser exibidos, por exemplo, no cabeçalho do relatório como o nome do estabelecimento ou perído. Uma dica: visite esta dica que lá mostra como exportar diretamente para PDF ou Excel sem ter que passar pelo processo de seleção no ReportViewer.

Adiquira o projeto e veja uma aplicação prontinha utilizando esses conceitos. Além de estar investindo em seu aprendizado está contribuindo para meus estudos e pesquisas. A implementação completa dos métodos fazem parte da Regisoft Library que voce também pode adquirir.

Bom, é isso. Obrigado pela atenção e até a próxima.