.NET

23 out, 2012

Explorando Microsoft SQL Reporting Services – Parte 03

Publicidade

Olá, pessoal! Nesse terceiro artigo da série vamos trabalhar com vários exemplos dos relatórios Local Mode – lembrando que todos os códigos aqui implementados estão disponíveis, só entrar em contato.

Parte 3 – local mode – demos

A seguir, criaremos alguns relatórios para exemplificar o que já vimos até então, bem como alguns recursos que veremos com os relatórios que vamos criar. Nossos exemplos são baseados no modelo de dados apresentado na parte dois do nosso artigo, que relaciona pedidos, itens de pedido, produtos e vendedores.

Relatório tabular

Nesse exemplo, criaremos um relatório que nos permite visualizar a relação de produtos, suas respectivas categorias, total em estoque e valor unitário. O usuário desse relatório pode selecionar uma ou mais categorias de produtos que deseja visualizar. O relatório faz uso de formatação condicional para destacar as quantidades em estoque se esse for inferior a 250, também faremos uso dos recursos de formatação de moeda e ordenação da coluna: “Nome do Produto”.

Criando o relatório

Esse relatório exibe as colunas com o nome, categoria, total em estoque e valor unitário de cada produto.

Figura 1  – Datatable Produtos Estoque
Figura 1 – Datatable Produtos Estoque
  •  Primeiro passo: construção do DataSet

Adicionar um objeto dataSet com o nome Tabular (vide sessão “Repositório de dados Local – DataSet”) à aplicação na pasta DataSources, e adicionar a ele um datatable com a estrutura da figura 1.

Esse datatable será preenchido com os dados provenientes do resultado da seguinte stored procedure: getProdutosinCategorias, que recebe como parametro uma string com as identificações das categorias separadas por vírgula.

  • Segundo passo: criação e modelagem do relatório

Incluiremos um novo relatório chamado TBProdutosporCategoria, em nosso projeto. Ele estará localizado na pasta Reports (vide artigos anteriores). Usando um objeto Table da toolbox dos relatórios, criaremos a estrutura do relatório formatado, conforme a figura abaixo:

Figura 2 – relatório tabular
Figura 2 – relatório tabular
  • Terceiro passo: formatar o relatório

Destacaremos os itens da coluna de estoque com valor inferior a 250; para tal, selecionamos a janela de propriedades da caixa de texto e no atributo Color, selecionamos Expressions. Então criamos uma instrução da seguinte forma:

=IIf(Fields!QT_ESTOQUE.Value<250,"Red","Blue")

Em seguida, adicionamos as funcionalidades de ordenação nas colunas; para tal, basta configurar a caixa de texto “Nome Produto”, na tab Interative Sort, como na figura abaixo:

Figura 3 – ordenação colunas
Figura 3 – ordenação colunas

Criando o cliente

Para configuração do cliente, adicionamos e configuramos um controle ReportViewer. Em seguida, adicionamos o código cliente para carga do dataTable e a configuração do reportViewer criado. A seguir, apresentamos um trecho do código para carga da datatable e configuração do reportViewer com destaque para passagem dos parâmetros na stored procedure, utilizada para carga do datatable, idscategoria.

 SqlParameter[] parms = {

new SqlParameter("@idCategorias", SqlDbType.VarChar,20)

};

parms[0].Value = getIdCategorias(); //método auxiliar que recupera as categorias da interface do usuário.

cmdReport.CommandType = CommandType.StoredProcedure;

cmdReport.Connection = conReport;

foreach (SqlParameter parm in parms)

cmdReport.Parameters.Add(parm);

cmdReport.CommandText = "getProdutosinCategorias";

drReport = cmdReport.ExecuteReader();

dsReport.Tables[0].Load(drReport);

drReport.Close();

conReport.Close();

rptViewTable.LocalReport.ReportPath = "Reports//TBProdutosporCategoria.rdlc";

ReportDataSource rds = new ReportDataSource();

rds.Name = "Tabular_ProdutosEstoque";

rds.Value = dsReport.Tables[0];

rptViewTable.LocalReport.DataSources.Clear();

rptViewTable.LocalReport.DataSources.Add(rds);

this.rptViewTable.RefreshReport();

Finalmente eis nosso relatório em ação:

Figura  4 – relatório em ação
Figura 4 – relatório em ação

Relatório master-detail

 

Nesse exemplo criaremos um relatório que nos permite visualizar pedidos e seus respectivos itens. Para criação do master-detail, faremos uso da funcionalidade de subreports com parâmetros para relacionar o relatório principal (lista de pedidos) e seus respectivos itens.

Criando o relatório Detail

Começaremos com a construção do relatório que será o “detail” da nossa implementação. Esse relatório exibe duas colunas com a descrição do produto do pedido, e sua respectiva quantidade vendida.

    • Primeiro passo: construção do DataSet.

 

Adicionar um objeto dataSet com o nome MasterDetail (vide sessão “Repositório de dados Local – DataSet”) à aplicação na pasta DataSources, e adicionar a ele um datatable com a estrutura da figura abaixo.

Figura 5 – datatable Itens do Pedido
Figura 5 – datatable Itens do Pedido

 

 Esse datatable será preenchido com os dados provenientes do resultado da seguinte instrução SQL: SELECT [ITE].ID_PEDIDO, [PRO].DS_PRODUTO, [ITE].QT_PRODUTO FROM TB_ITENS_PEDIDO [ITE] INNER JOIN TB_PRODUTO [PRO] ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO

    • Segundo passo: criação e modelagem do relatório.

 

Incluiremos um novo relatório em nosso projeto chamado MDItensPedidona pasta Reports. Usando um objeto Table da toolbox dos relatórios, criaremos a estrutura do relatório formatado conforme a figura abaixo:

Figura 6 – relatório detail
Figura 6 – relatório detail
    • Terceiro passo: criar o parâmetro para associar ao “Master”

 

Aqui criaremos o parâmetro (vide sessão “Parametrização”) que será o link com o relatório “Master”. Esse parâmetro chamaremos de idPedido do tipo Integer e “Hidden”.

Figura 7 – configurando filtro
Figura 7 – configurando filtro
    • Quarto passo: criar um filtro

 

Através das propriedades da tabela criada no segundo passo, criaremos um filtro dos dados do relatório, onde a identificação do pedido será aquela correspondente ao parâmetro criado no terceiro passo. A figura abaixo ilustra a operação.

 Criando o relatório Master

Na criação do relatório “master”, exibimos a identificação do pedido, o nome do vendedor, a data do pedido e o valor em reais da venda do pedido. O grande diferencial desse relatório é a inclusão do item Subreport como se fosse uma coluna de uma table e configurar o subreport para associar o campo de identificação do pedido ao seu parâmetro.

    • Primeiro passo: construção do Datatable no DataSet.

 

Adicionar um datatable ao nosso Dataset com a estrutura da figura abaixo. Esse datatable será preenchido com os dados provenientes do resultado da seguinte instrução SQL: SELECT [ped].ID_PEDIDO,  [VEN].NO_VENDEDOR, CONVERT(SMALLDATETIME,  [PED].DT_PEDIDO, 103) as DT_PEDIDO, SUM([ITE].QT_PRODUTO*[PRO].VL_PRECO) as [Valor do Pedido]  FROM TB_PEDIDO [PED] INNER JOIN TB_ITENS_PEDIDO [ITE] ON [PED].ID_PEDIDO = [ITE].ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR GROUP BY  [ped].ID_pedido,[VEN].NO_VENDEDOR, [PED].DT_PEDIDO.

Figura 8 – DataTable do Pedido
Figura 8 – DataTable do Pedido
    •  Segundo passo: criação e modelagem do relatório

 

Incluiremos um novo relatório chamado MDPedido, que estará na pasta Reports. Usando um objeto Table da toolbox dos relatórios, criaremos a estrutura do relatório formatado conforme a figura abaixo:

Figura 9 – relatório master
Figura 9 – relatório master
    • Terceiro passo: configurar  o subreport

 

Aqui configuraremos o item subreport de modo a estabelecer o vínculo entre o relatório master e o detail através do parâmetro, idPedido, criado no relatório Detail. Essa configuração é feita nas propriedades do subreport, a tab Parameters, como ilustra a figura:

Figura 10 – parâmetros do subReport
Figura 10 – parâmetros do subReport

 

Criando o cliente

Para configuração do cliente, adicionamos e configuramos um controle ReportViewer. Em seguida, adicionamos o código cliente para carga dos dataTables e configuração do reportViewer criado. A seguir, apresentamos um trecho do código para carga das duas datatables e configuração do reportViewer. A primeira instrução (em vermelho) carrega a tabela Pedido e a segunda a ItensPedido. Vemos também que só configuramos o datasource do relatório “master”, e o relatório “detail” a seguir:

cmdReport.CommandType = CommandType.Text;

cmdReport.Connection = conReport;

cmdReport.CommandText = "SELECT [ped].ID_PEDIDO,  [VEN].NO_VENDEDOR, CONVERT(SMALLDATETIME,  [PED].DT_PEDIDO, 103) as DT_PEDIDO, SUM([ITE].QT_PRODUTO*[PRO].VL_PRECO) as [Valor do Pedido]  FROM TB_PEDIDO [PED] INNER JOIN TB_ITENS_PEDIDO [ITE] ON [PED].ID_PEDIDO = [ITE].ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR GROUP BY  [ped].ID_pedido,[VEN].NO_VENDEDOR, [PED].DT_PEDIDO ; SELECT [ITE].ID_PEDIDO, [PRO].DS_PRODUTO, [ITE].QT_PRODUTO FROM TB_ITENS_PEDIDO [ITE] INNER JOIN TB_PRODUTO [PRO] ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO";

drReport = cmdReport.ExecuteReader();

dsReport.Load(drReport,LoadOption.OverwriteChanges,dsReport.Tables[0],dsReport.Tables[1]);

drReport.Close();

conReport.Close();

rptViewMasterDetail.LocalReport.ReportPath = "..//..//Reports//MDPedido.rdlc";

ReportDataSource rds = new ReportDataSource();

rds.Name = "MasterDetail_Pedido";

rds.Value = dsReport.Tables[0];

rptViewMasterDetail.LocalReport.DataSources.Clear();

rptViewMasterDetail.LocalReport.DataSources.Add(rds);

rptViewMasterDetail.RefreshReport();

 

Finalmente eis nosso relatório em ação:

Figura 11 – relatório master-detail
Figura 11 – relatório master-detail

Relatório gráfico

Nesse exemplo, criaremos um relatório que nos permite visualizar graficamente as vendas, em reais, dos nossos vendedores por período. Nesse relatório, faremos uso da funcionalidade Chart da toolbox dos relatórios. O período das vendas a serem consultadas será passado como parâmetro para instrução SQL, que fará a busca no banco de dados, o que é uma alternativa mais prudente que o uso de filtros no relatório, já que não necessitamos recuperar todos os registros das vendas.

Criando o relatório

Esse relatório correlaciona duas informações para gerar nosso gráfico: nome do vendedor e o total de sua venda.

  • Primeiro passo: construção do DataSet.

Adicionar um objeto dataSet com o nome Gráfico (vide sessão “Repositório de dados Local – DataSet”) à aplicação na pasta DataSources, e adicionar à ele um datatable com a estrutura da figura abaixo.

Figura 12 – DataTable Vendas
Figura 12 – DataTable Vendas

Esse datatable será preenchido com os dados provenientes do resultado da seguinte instrução SQL: SELECT [VEN].NO_VENDEDOR,   SUM([ITE].QT_PRODUTO*[PRO].VL_PRECO) as [Valor do Pedido] FROM TB_PEDIDO [PED] INNER JOIN TB_ITENS_PEDIDO [ITE] ON [PED].ID_PEDIDO = [ITE].ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ON  [ITE].ID_PRODUTO = [PRO].ID_PRODUTO INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR WHERE CONVERT(SMALLDATETIME,  [PED].DT_PEDIDO, 103) BETWEEN ’99/99/9999′ AND ’99/99/9999′ GROUP BY  [VEN].NO_VENDEDOR

  • Segundo passo: criação e modelagem do relatório.

Incluiremos um novo relatório chamado GrVendas, na pasta Reports. Usando um objeto Chart da toolbox dos relatórios, criaremos a estrutura do relatório formatado conforme a figura abaixo:

Figura 13 – formatando relatório chart
Figura 13 – formatando relatório chart
  • Terceiro passo: configurar o relatório

Aqui configuraremos o item Chart de modo a torná-lo parecido ao exibido na imagem acima.

  •  Quarto passo: criar os parâmetros do período

Nosso relatório também exibe o período da consulta que é exibido na sessão header do relatório. Para recuperar essas informações fornecidas pelo cliente, recorremos aos parâmetros, dtInicio e dtFim – esta configuração é feita nas propriedade do relatório, na tab Parameters.

 Criando o cliente

Para a configuração do cliente, adicionamos e configuramos um controle ReportViewer. Em seguida, adicionamos o código cliente para carga do dataTable e configuração do reportViewer criado. A seguir, apresentamos um trecho do código para carga da datatable e configuração do reportViewer com destaque para passagem dos parâmetros dtInicio e dtFim.

 cmdReport.CommandType = CommandType.Text;

cmdReport.Connection = conReport;

cmdReport.CommandText = "SELECT [VEN].NO_VENDEDOR, SUM([ITE].QT_PRODUTO*[PRO].VL_PRECO) as [Valor do Pedido] FROM TB_PEDIDO [PED] INNER JOIN TB_ITENS_PEDIDO [ITE] ON [PED].ID_PEDIDO = [ITE].ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR WHERE CONVERT(SMALLDATETIME,  [PED].DT_PEDIDO, 103) BETWEEN CONVERT(SMALLDATETIME,'" + txtDtInicio.Text + "',103) AND CONVERT(SMALLDATETIME,'" + txtDtFim.Text + "',103) GROUP BY  [VEN].NO_VENDEDOR";

drReport = cmdReport.ExecuteReader();

dsReport.Tables[0].Load(drReport);

drReport.Close();

conReport.Close();

rptViewGrafico.LocalReport.ReportPath = "..//..//Reports//GrVendas.rdlc";

ReportParameter[] parPeriodo = { new  ReportParameter("dtInicio",txtDtInicio.Text), new

                  ReportParameter("dtFim",txtDtFim.Text)};

rptViewGrafico.LocalReport.SetParameters(parPeriodo);

ReportDataSource rds = new ReportDataSource();

rds.Name = "Grafico_Vendas";

rds.Value = dsReport.Tables[0];

rptViewGrafico.LocalReport.DataSources.Clear();

rptViewGrafico.LocalReport.DataSources.Add(rds);

rptViewGrafico.RefreshReport();

Finalmente eis nosso relatório em ação:

Figura 14 – relatório chart em ação
Figura 14 – relatório chart em ação

Relatório document map

Nesse exemplo, criaremos um relatório que nos permite visualizar pedidos, seus respectivos itens e o valor total do pedido dentro de um período informado pelo usuário. Utilizaremos um recurso chamado DocumentMap, onde listamos os vendedores e seus respectivos pedidos com recurso de um link para os detalhes do vendedor ou do pedido.

Criando o relatório

Esse relatório lista os vendedores, seus pedidos e detalhes do pedido, com recurso de navegação via Document Map.

Primeiro passo: construção do DataSet.

Adicionar um objeto dataSet com o nome DocumentMap (vide sessão “Repositório de dados Local – DataSet”) à aplicação na pasta DataSources, e adicionar à ele um datatable com a estrutura da figura abaixo.

 Figura 15 –datatable Peddo
Figura 15 –datatable Peddo

Esse datatable será preenchido com os dados provenientes do resultado da seguinte instrução SQL: SELECT [PED].ID_PEDIDO, [PED].ID_VENDEDOR,[VEN].NO_VENDEDOR, [PED].DT_PEDIDO ,[pro].DS_PRODUTO, [ite].QT_PRODUTO, [pro].VL_PRECO FROM TB_PEDIDO [PED] INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR INNER JOIN TB_ITENS_PEDIDO [ITE] ON [PED].ID_PEDIDO= ITE.ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ON ITE.ID_PRODUTO = PRO.ID_PRODUTO

  • Segundo passo: criação e modelagem do relatório.

Incluiremos um novo relatório chamado DMapPedido, na pasta Reports. Usando um objeto Table da toolbox dos relatórios, criaremos a estrutura do relatório formatado conforme a figura abaixo:

Figura 16 – formatando relatório Document Map
Figura 16 – formatando relatório Document Map
  • Terceiro passo: configurar o relatório

Aqui configuraremos o item Table, de modo a torná-lo parecido ao exibido na imagem acima. Para tal, faremos uso de uma das propriedades mais poderosas das tabelas, que é a tab Groups. Essa propriedade nos permite, como o nome diz, agrupar os registros por um ou mais campos, similar à cláusula GROUP BY do T-SQL. Na figura 16 percebe-se que fizemos dois agrupamentos, 1 e 2, respectivamente, pelos campos NO_VENDEDOR e ID_PEDIDO.

Começamos nossa configuração criando um relatório com os atributos acima, configurando-o como um relatório tabular. Em seguida, nas propriedades da tabela, criamos os agrupamentos nomeados table1_grpVendedor e table1_grpPedido, necessariamente nessa ordem, conforme a imagem abaixo (Figura 17).

Figura 17 – criando grupos do relatório Document Map
Figura 17 – criando grupos do relatório Document Map

 

Em seguida, na mesma caixa de edição do grupo, configuramos o recurso de Document Map, que corresponde a um dos recursos de navegação dos relatórios do Reporting Services. Essa configuração é feita simplesmente especificando o Document Map Label de cada grupo. Para o primeiro grupo, utilizamos o campo correspondente ao nome do vendedor. No segundo, sofisticamos com a criação de uma expressão que concatena uma string com o campo de identificação do pedido. Finalmente movemos os campos nome do vendedor e identificação do pedido para as linhas de cabeçalho dos seus respectivos grupos.

Outro elemento interessante em nosso relatório, e muito comum em relatórios com agrupamento, são os totalizadores. No nosso relatório, sumarizamos o total do pedido em uma caixa de texto posicionada na área de rodapé do agrupamento de pedidos, com uma expressão que soma os valores individuais de cada produto multiplicado pela quantidade vendida, codificado da seguinte forma:

=Sum(Fields!QT_PRODUTO.Value*Fields!VL_PRECO.Value)

Finalmente, formatamos as caixas de texto com data e moeda, bem como as cores de fundo das linhas.

  • Quarto passo: criar os parâmetros do período

Nosso relatório também exibe o período da consulta, que é exibido na sessão header do relatório. Para recuperar essas informações fornecidas pelo cliente, recorremos aos parâmetros, dtInicio e dtFim. E essa configuração é feita nas propriedades do relatório – tab Parameters.

Criando o cliente

Para configuração do cliente, adicionamos e configuramos um controle ReportViewer. Em seguida, adicionamos o código cliente para carga do DataTable e configuração do reportViewer criado. A seguir apresentamos um trecho do código para carga da datatable e configuração do reportViewer com destaque para passagem dos parâmetros dtInicio e dtFim.

 cmdReport.CommandType = CommandType.Text;

cmdReport.Connection = conReport;

cmdReport.CommandText = "SELECT [PED].ID_PEDIDO, [PED].ID_VENDEDOR,[VEN].NO_VENDEDOR, [PED].DT_PEDIDO,[pro].DS_PRODUTO, [ite].QT_PRODUTO, [pro].VL_PRECO FROM TB_PEDIDO [PED] INNER JOIN TB_VENDEDOR [VEN] ON [PED].ID_VENDEDOR = [VEN].ID_VENDEDOR INNER JOIN  TB_ITENS_PEDIDO[ITE] ON [PED].ID_PEDIDO = [ITE].ID_PEDIDO INNER JOIN TB_PRODUTO [PRO] ”;

cmdReport.CommandText += " ON [ITE].ID_PRODUTO = [PRO].ID_PRODUTO WHERE CONVERT(SMALLDATETIME,[ped].DT_PEDIDO,103) BETWEEN CONVERT(SMALLDATETIME,'" +

txtDMdtInicio.Text + "',103) AND CONVERT(SMALLDATETIME,'" + txtDMdtFim.Text + "',103)";

drReport = cmdReport.ExecuteReader();

dsReport.Tables[0].Load(drReport);

drReport.Close();

conReport.Close();

rptViewGrafico.LocalReport.ReportPath = "..//..//Reports//DMapPedido.rdlc";

ReportParameter[] parPeriodo = { new  ReportParameter("dtInicio",txtDMdtInicio.Text), new

                  ReportParameter("dtFim",txtDMdtFim.Text)};

rptViewGrafico.LocalReport.SetParameters(parPeriodo);

ReportDataSource rds = new ReportDataSource();

rds.Name = "DocumentMap_Pedido";

rds.Value = dsReport.Tables[0];

rptViewGrafico.LocalReport.DataSources.Clear();

rptViewGrafico.LocalReport.DataSources.Add(rds);

rptViewGrafico.RefreshReport();

Finalmente eis nosso relatório em ação:

Figura 18 – relatório Document Map em ação
Figura 18 – relatório Document Map em ação

 

Limitações

Os relatórios Local-mode são uma excelente alternativa para pequenas e médias aplicações onde os relatórios podem compartilhar recursos dos sistemas e não dispomos de uma infra-estrutura mais elaborada. Abaixo, relacionamos alguns dos itens que apontamos como limitações desse modelo de relatórios:

  • Só exporta para os formatos Excel e PDF;
  • Não suporta interface customizada;
  • Não disponibiliza interface aos usuários para os parâmetros;
  • Document map não suportado em FireFox;
  • Compartilha os recursos da aplicação cliente.

É isso ai, pessoal! No próximoartigo, uma verdadeira revolução: os relatórios remote mode. Simplesmente imperdível! Até lá.