sábado, 6 de novembro de 2010

Trabalhando com Reports Dinamicamente

Além de suas funcionalidades primordiais para manutenção de dados, sistemas costumam exigir uma área gerencial que permita a visualização dos dados manipulados. Para tal é comum utilizar ferramentas de relatório do .NET, tais como Crystal Reports ou Reports.
Reports associados com seu Report Viewer devem ser conectados a base de dados de maneira que aceite os filtros necessários para atender aos critérios do cliente. Quando pesquisamos por conteúdo que demonstre a utilização desta ferramenta, é comum encontrar tutoriais e/ou artigos que demonstrem sua utilização, porém com um velho vicio de desenvolvedores em ASP.NET ou Windows Form, o famoso “clica e arrasta”. São poucos os artigos que ensinem o leitor a popular a criar, popular e vincular um DataSet ao Report de forma dinâmica.
O objetivo deste artigo é demonstrar de maneira simples como criar um DataSet de maneira programática e vinculá-lo ao Report. Neste exemplo utilizaremos a base de exemplo da Microsoft AdventureWorks. O Report irá listar os empregados e seus respectivos cargos, a figura 1 mostra o Database Diagram do SQL Server com as tabelas que utilizaremos. Para fazer download do AdventureWorks acesse o link http://sqlserversamples.codeplex.com/.

Figura 1 Diagrama da Base utilizada

Nosso projeto será simples, terá uma classe de acesso a dados, uma página de filtros e uma página contendo o ReportViewer, além do Report.rdlc é claro.
Para iniciar abra o Visual Studio e vá a novo Projeto -> ASP.NET WebSite, conforme figura 2.

Figura 2 Criando o Projeto

A figura 3 mostra a tela de criação do projeto, como utilizaremos o servidor interno do Visual Studio para executar o projeto, recomendo deixar selecionado File System na caixa de seleção Web Location, assim podemos indicar um diretório físico para o projeto, que demos o nome de “PopulandoReport”.


Figura 3 Salvando o Projeto

O primeiro passo para implementar nosso projeto é acessar a base de dados e retornar os dados que queremos, como o objetivo desse artigo é demonstrar a utilização dinâmica do ReportViewer, nossa classe de acesso a dados será simples e ficará na pasta App_Code do projeto. Para criar a classe EmpregadoDataAccess, clique com o botão direto do mouse sobre o projeto -> Add New Item e escolha Class, assim como exibido na figura  4.

Figura 4 Adicionando a Classe EmpregadoDataAccess




Ao clicar em Add o Visual Studio irá sugerir que seja criada a pasta App_Code ao projeto e adicione a nossa classe dentro dela, clique em sim e a classe será criada  normalmente. Note que a estrutura da classe é simples, teremos um construtor e um método: GetEmployees.
A listagem 1 apresenta o código da classe, note que utilizamos a instrução using para garantir que o Garbage Collector entre em ação para limpar os recursos utilizados. Por boas práticas não recomendamos a utilização da connectionstring direto no código fonte e sim, no Web.Config da aplicação, como este é apenas um código de exemplo será utilizado diretamente. Outro ponto importante é a utilização de parâmetros na query, parâmetros além de serem boa prática, também agregam segurança, reduzindo os riscos de Sql Injection.

Listagem 1 Classe EmpregadoDataAccess

Em nossa página default serão adicionados um DropDownList, o qual popularemos com alguns cargos, um Button para o submit e o ReportViewer, para geração do Report. Para adicionar o ReportViewer expanda a  toolbox do visual Studio, clique em Reporting, então clique sobre  ReportViewer e arraste para dentro da página, a figura 5 exibe o controle exatamente o controle a ser selecionado. Neste ponto é recomendada a utilização do “Clica e Arrasta”, pois conforme pode ser visto nas figuras 6 e 7, o visual Studio adiciona as referências necessárias para utilização de Reports na Página e no Web.Config.

Figura 5 Selecionando o Report Viewer

Figura 6 Registrando o Assembly para utilização de reports

Figura 7 Assembly registrado no Web.Config




Por questão de organização iremos adicionar duas pastas ao nosso projeto: 1) report – irá abrigar o nosso Report.rdlc e; 2) xsd – onde será salvo o nosso DataSet gerado dinamicamente. Então sem mais delongas vamos a .cs de nossa Default.aspx para inciarmos a programação. Antes de abrir a default.aspx.cs dê dois cliques sobre o botão para que o visual Studio adicione automaticamente o evento necessário para a pesquisa de dados do relatório.
Dentro do evento gerado iremos receber o valor selecionado no DropDownList de cargos e instanciar nossa Classe EmpregadoDataAccess. O próximo passo é criar um DataSet que recebe o retorno do método GetEmployess, veja a Listagem 2.

Listagem 2 Estrutura Default.aspx.cs

O próximo passo é adicionar logo abaixo da linha de criação do dataset, a instrução para que seja criado o DataSet físico no projeto, para isso utilizamos o método WriteXmlSchema da classe DataSet, veja Listagem 3. Execute o projeto pressionando Ctrl + F5, logo após vá a pasta xsd e pressione F5 para atualizar seu conteúdo.

Listagem 3 Criando o DataSet

Abra o DataSet gerado e note que ele possui somente uma Table, correspondente ao resultado de nossa query, os campos da Table são exatamente os chamados no select, assim como vemos na Figura 8. É importante lembrar que o método WriteXmlSchema é necessário ser executado somente uma vez, para geração do xml, após recomendo que comente a linha com a chamada do método.

Figura 8 DataSet Gerado

O próximo passo é trabalhar nosso Report, para isso clique com o botão direito sobre a pasta Report-> Add New Item... Report. Em nosso projeto, chamaremos o report de ReportEmpregado, confira na Figura 9.

Figura 9 Adicionando o Report

Com o Report aberto expanda ToolBox e arraste uma Table, o visual Studio irá solicitar vinculação de um dataset, a figura 10 exibe a tela de vinculação. Escolha nosso DataSet criado para vincular a Table.  Note que se estiver utilizando o Visual Studio 2008, o procedimento para vincular o DataSet ao Report é diferente, para isso vá em Report, na barra de ferramentas, selecione DataSources e escolha o datasource desejado.

Figura 10 Vinculando DataSet

Em sua Table adicione os campos e seus valores, basta clicar sobre a célula, selecionar Expression e então utilizar a Expressão =Fields![NomeCampo].Value, onde [NomeCampo] corresponde ao nome do campo que deseja exibir, conforme a Figura 11. O report possui inúmeras funções que possibilitam a manipulação de dados, como somar, contar, formatação de dados, vale a pena conferir.

Figura 11 Adicionando valores às colunas

Voltando ao nosso evento no código da Default.aspx.cs adicionaremos algumas linhas de código, para vincular o dataset e o report ao ReportViewer da pagina, assim poderemos executar nossa pesquisa e visualizar o relatório. A primeira coisa a fazer é criar um objeto do tipo ReportDataSource e vinculá-lo ao DataSet, utilizaremos duas propriedades do objeto: Name e Value. Name receberá o nome dado ao DataSet no momento da criação da Table no report, em nosso projeto foi DataSetEmployees. Value receberá o objeto de nosso DataSet já populado anteriormente, na Listagem 4 podemos ver esta alteração.

Listagem 4 Criando o ReportDataSource

A seguir criamos uma string indicando o endereço do Report. Feito isto estamos finalizando nosso projeto, agora basta atribuir os objetos ao ReportViewer da Página. Para atribuir o datasource ao ReportViewer utilizaremos o método Add da ReportDataSourceCollection do Report, this.ReportViewer1.LocalReport.DataSources.Add. Por se tratar de uma Collection podemos atribuir quantos ReportDataSource quisermos. O endereço do report é adicionado por meio da propriedate ReportPath, this.ReportViewer1.LocalReport.ReportPath, veja a Listagem 5 para maior detalhe.

Listagem 5 Adicionando parâmetros ao ReportViewer

Agora basta executar o projeto e ver o resultado, a figura 12 exibe o relatório sendo gerado corretamente. Cada vez que clicamos no botão consultar nosso filtro é aplicado.

Listagem 6 Visualização do Relatório

Para criação de consultas personalizadas e criação de relatórios com Report sem precisar adicionar query diretamente nas propriedades do DataSet para vinculá-lo. A possibilidade de parametrizar o report dinamicamente via código facilita na hora de criar o DataSet e trabalhar com diferentes reports em um só ReportViewer, eliminando a necessidade de criar varias paginas para cada report. Lembre-se que o ReportViewer possui varias propriedades e vale a pena explorá-las.












22 comentários:

  1. É na hora de implementar programaticamente que separam-se meninos e adultos.
    O mercado tá cheio de gente que se diz profissional mas não faz idéia do que acontece por trás do clica e arrasta.

    Parabéns pelo post!

    ResponderExcluir
  2. Parabens pelo post, era exactamente isto que eu precisava....

    Cumprimentos

    ResponderExcluir
  3. Fiz esse seu exemplo no meu sistema e no final tá me retornando a seguinte mensagem:
    A data source instance has not been supplied for the data source 'DataSet1'.

    ResponderExcluir
    Respostas
    1. Esse "DataSet1" deve ser o mesmo nome do dataset que voce criou para o report. No código do post é o "DataSetEmployees"

      Excluir
  4. Fernando tenho um relatorio que adicionei um tabeladapter e adicionei os campos dele ao report, mais queria alterar o select do tableadapter dinamicamente eu teria como fazer isso, tipo assim, tenho um radiobuttonlist onde seleciono 1 - aberto 2 - concluido onde conforme a opção altero no select o where de um campo data para is null ou not null.

    ResponderExcluir
  5. Fernando segui o seu passo a passo sendo que qdo vou vincular o dataset criado ou report ele não me dá a opção de seleciona-lo, estou usando o vs2010, qdo clico em reportdata e new dataset o dataset criado nao aparece na lista, como faço para ele aparecer ?

    ResponderExcluir
    Respostas
    1. Junior, boa tarde!

      Observei que estou com mesmo problema, conseguiu solucionar?

      Sds,
      Diego

      Excluir
  6. Fernando, Parabéns pelo tutorial. Obrigado

    ResponderExcluir
  7. Adicionei uma linha ao código do método do Button1_click

    this.ReportViewer1.LocalReport.DataSources.Clear();

    no meu caso o DataSource não atualizava entre um filtro e outro. Fiz isso e tudo ok.

    ResponderExcluir
  8. Fernando, segui todo o passo a passo, mas quando crio o report não consigo visualizar o dataset criado. O que posso ter feito de errado?

    ResponderExcluir
  9. Fernando, quando aplico o filtro este nao funciona. Ja conferi o codigo esta igual, como posso faze-lo

    ResponderExcluir
  10. URGENTE por favor como fazer isso em crystalreport com vs 2010?

    ResponderExcluir
  11. Olá, qual é o comando para windows form referente a Server.MapPath?

    ResponderExcluir
  12. Ótimo tutorial. Mas eu preciso fazer isso com MVC 3 + Razor. Vc em algum tutorial para indicar, só acho com configuração prontas e não programando igual ao seu.

    ResponderExcluir
  13. Olá como coloco subtotal de uma coluna por página e um total geral na ultima página.

    ResponderExcluir
  14. Show de bola.

    Estou utilizando esse código em um projeto windowsForms, só que não estou conseguindo criar dinamicamente o dataSet porque o método .WriteXmlSchema() não aceita os parâmetros passados no código.

    como que faço para criar um dataSet no WindowsForms ?

    dificuldade está nessa linha abaixo

    // Cria um dataSet físico no projeto
    // DataSetEmpregados.WriteXmlSchema(parâmetros.);

    obrigado

    ResponderExcluir
  15. Como faço para conseguir este projeto pois não conseguir criar um e estou precisando urgentemente.
    Meu Email: adao_lucas_2020@hotmail.com
    desde já agradeço.

    ResponderExcluir
  16. aaaah, mentira que é WEB cara =/
    to faz 2 semanas procurando um relatorio dinamico em codigo..e agora que acho ta web :(
    alguem sabe uma versao em form?

    ResponderExcluir
  17. Obrigada Fernando, seu post ajudou bastante!
    Abraço!

    ResponderExcluir