menu
Fórum Adianti
menu Menu
Relatórios com queries complexas de maneira Orientada a Objetos Em outro artigo (http://www.adianti.com.br/forum/pt/view_876), eu explico que devemos privilegiar o uso de objetos, seus métodos e relacionamentos mais do que o uso de SQL em uma aplicação de negócios. Devemos sempre que possível usar mecanismos do próprio framework para cuidar da persistência dos objetos - como o Active Record - e dos relacionamentos entre eles. Na grande maioria das situa...
PD
Relatórios com queries complexas de maneira Orientada a Objetos  
Fechado
Em outro artigo (www.adianti.com.br/forum/pt/view_876), eu explico que devemos privilegiar o uso de objetos, seus métodos e relacionamentos mais do que o uso de SQL em uma aplicação de negócios. Devemos sempre que possível usar mecanismos do próprio framework para cuidar da persistência dos objetos - como o Active Record - e dos relacionamentos entre eles. Na grande maioria das situações (formulários de inserção e atualização, datagrids com listagens e delação de registros), podemos usar os mecanismos do próprio framework para persistência, como os métodos store(), load() e delete() da classe TRecord (que manipula um objeto de cada vez), bem como os métodos load(), delete() e count() da classe TRepository (que manipula um conjunto de objetos). Devemos deixar as complexas expressões SQL somente para os casos em que elas são realmente necessárias.

Uma situação em que o usos e instruções SQL é praticamente indispensável é em relatórios. Por que em relatórios frequentemente precisamos cruzar muitas tabelas, fazer uso de subconsultas, expressões matemáticas, bem como recursos específicos do banco de dados (funções de georreferência, geométricas, data warehouse, etc). Além disso, existem consultas cujo resultado só faz sentido a partir do cruzamento de várias tabelas. Realizar tais operações usando apenas objetos teria um custo muito alto, tendo em vista que para montar um relatório teríamos de percorrer milhares de objetos de uma classe e, a partir desses, buscar informações em objetos relacionados. Claro que essas questões de desempenho caem por terra com o advento de novas tecnologias que permitem o uso de banco de dados em memória. Mas como isso ainda não é uma realidade para as maiorias, vamos adotar uma estratégia simples e funcional.

Então, como fazer um relatório usando o Adianti Framework? A maneira mais simples é criar uma VIEW no banco de dados para encapsular o SQL do relatório, e a partir de então manipular essa VIEW por meio de uma classe Active Record (TRecord) e repositório (TRepository).

Vamos imaginar que nossa query busca dados de pessoas e títulos, onde os títulos já estão vencidos e as pessoas residem na cidade cujo ID=10. Claro que essa é uma query bastante simples. Mas para nosso exemplo é suficiente. Poderíamos pensar aqui queries cruzando até 10 tabelas, como regras de negócio complexas, mas isso não mudaria a didática do exemplo.

SELECT p.id, p.nome, p.email, t.valor, t.vencimento FROM pessoas p, titulos t WHERE t.pessoa_id = p.id AND t.vencimento < date(now()) AND p.cidade_id = 10


Então criamos uma VIEW para representar essa query no banco de dados. Podemos apagar e recriar essa query quantas vezes quisermos, para adicionar ou remover colunas, regras, dentre outros. Vamos usar o prefixo "view_" para facilitar a visualização desta entidade na base de dados. Veja que deixamos o filtro (p.cidade_id = 10) de fora, pois pretendemos usar esta VIEW para gerar relatório de títulos vencidos para diferentes cidades.

CREATE VIEW view_titulos_vencidos AS SELECT p.id as pessoa_id, p.nome as pessoa_nome, p.email as pessoa_email, p.cidade_id as cidade_id, t.valor as titulo_valor, t.vencimento as titulo_vencimento FROM pessoas p, titulos t WHERE t.pessoa_id = p.id AND t.vencimento < date(now())


O próximo passo é definir uma classe (Active Record) que represente essa entidade do banco de dados para a aplicação. Usaremos o prefixo “View” para diferenciar objetos dessa classe dos demais objetos do modelo da aplicação. É importante salientar que não realizaremos operações como store() ou delete() neste objeto, por tratar-se de uma VIEW. Mas realizaremos carga de objetos (TRepository), por isso precisaremos declarar esta classe.

  1. <?php
  2. class ViewTitulosVencidos extends TRecord
  3. {
  4.     const TABLENAME 'view_titulos_vencidos';
  5.     const PRIMARYKEY'id';
  6.     const IDPOLICY =  'max'// {max, serial}
  7. }
  8. ?>


A partir do momento em que temos a classe definida, podemos utilizar os mecanismos padrão do framework para realizar a carga de objetos. E para carregar os objetos em memória, podemos simplesmente utilizar a classe TRepository, responsável por manipular coleções de objetos (Active Record). No exemplo a seguir, estamos carregando em memória os objetos que representam títulos vencidos com o valor superior à R$ 100, e somente da cidade cujo ID=10.

  1. <?php
  2. $repo = new TRepository('ViewTitulosVencidos');
  3. $criteria = new TCriteria;
  4. $criteria->add(new TFilter('titulo_valor''>'100));
  5. $criteria->add(new TFilter('cidade_id''=''10'));
  6. $objetos $repo->load($criteria);
  7. foreach ($objetos as $objeto)
  8. {
  9.     print $objeto->pessoa_nome;
  10.     print $objeto->pessoa_email;
  11. }
  12. ?>


Para finalizar, podemos utilizar as classes padrão disponibilizadas pelo framework para criar os relatórios. O tutor já oferece um exemplo pronto de como gerar relatórios (www.adianti.com.br/framework_files/tutor/index.php?class=TabularRepo). Agora basta adaptar este exemplo para usar a View recém-criada.

Curso completo Meu Negócio Pronto
Use para si, ou transforme em um negócio: Inclui aulas e códigos-fontes
Gestor de conteúdo (SITE) + Loja Virtual (E-Commerce) + Emissor de Notas para infoprodutos


Meu negócio pronto Quero me inscrever agora!

Comentários (13)


LC

Pablo, alem de relatórios, da para criar grids usando Views ?
LC

Da sim.
FM

kkkkkkkk muito bom... vc pergunta e vc mesmo responde ... kkkkkkkkkkk
LC

Flavio, eu perguntei antes de testar, kkkkkk, depois eu fiz e deu certo, ai eu respondi, kkkkkk.
FM

eu entendi o que aconteceu.... tem vezes que ninguem responde antes de acharmos a soluçAo sozinho... foi bacana de sua parte ainda compartilhar que achou a slução.... mas ficou engraçado.. kkkkkkkk
abraços
PC

Bom Dia

Gostaria de saber se tem como implementar uma function (store procedure) no adianti, como faço para passar os parâmetros.

exemplo de uma função do postgre
public.cc_extrato(?i_data_inicial, ?i_data_final, ?i_id_pessoa)

tem como criar um TRecord de uma funcion, como implementar?

Att
Marcos Colla
PD

Patricia,

Por favor, abra um POST específico sobre sua dúvida, ok?

Att,
RR

Ótimo artigo! Me ajudou bastante num grid que precisei fazer com 3 tabelas... :)
JF

Sou iniciante nessa área, alguém teria um exemplo real colocando o código pra eu ver como realmente isso funciona, estou desenvolvendo um projeto mas essa parte de relacionamento ainsa esta bem confusa p mim...Agradeço desde já. Abraços
AL

Como faço para criar um botão de ação em um formulário, apontando para o form gerador de relatório?
RK

Muito esclarecedor esse artigo Pablo, me ajudou a superar uma dificuldade que enfrentava a alguns dias.
Obrigado!
JP

Alguem ai por favor me ajude a fazer um metodo de fatura no formulario mestre de talhe de vendas
JP

Alguem ai por favor me ajude a fazer um metodo de fatura no formulario mestre de talhe de vendas