07 procedures-curso gxxbr

56

Upload: cristiano-rafael-steffens

Post on 09-Jul-2015

1.462 views

Category:

Technology


3 download

DESCRIPTION

Genexus Course

TRANSCRIPT

Page 1: 07 procedures-curso gxxbr

���

Page 2: 07 procedures-curso gxxbr

���

Procedimentos:Definem processos não interativos de consulta e atualização da base de dados. Os procedimentospodem gerar um arquivo formato PDF, mediante o qual é possível listar informação na tela ouimpressora. Além disso, os procedimentos podem atualizar a base de datos1.

_____________________________________________________________________________1 Como veremos mais adiante, existe um tipo de dados especial, que não é estritamente um tipo dedados, mas algo um pouco mais complexo, o business component, por meio do qual serão realizadosatualizações a base de dados em qualquer objeto GeneXus. Portanto, utilizando variáveis de tipo dedados business component, poderão ser realizadas atualizações incluso nos objetos que pornatureza não oferecem esta possibilidade, como as web panels.

Page 3: 07 procedures-curso gxxbr

���

Definição proceduralA diferença das regras das transações onde as especificações se realizam de forma declarativa eGeneXus determina no momento de gerar o programa a seqüência de execução, nos procedimentosas especificações se realizam de forma procedural. Desta forma, a seqüência de execução édeterminada pelo analista, utilizando para isso uma linguagem simples que contem comandos decontrole, de impressão, de acesso a base de dados, etc.

Definição sobre a base de conhecimentoA grande potencia da linguagem dos procedimentos está que as definições são realizadas sobre abase de conhecimento e não diretamente sobre o modelo f�sico (tabelas, �ndices, etc.). Isto nos permiteutilizar autom�ticamente todo o conhecimento já incorporado ou gerado por GeneXus a partir dasespecificações realizadas.

Por exemplo, se desejamos mostrar o resultado de uma f�rmula é suficiente nomear o atributo f�rmulano lugar adequado e GeneXus dispara o c�lculo mostrando o resultado, sem necessidade do analistaoferecer nenhuma outra informação. A informação de como se calcula um atributo f�rmula est� contidana base de conhecimento.

Também podemos utilizar o conceito de tabela estendida, já que GeneXus conhece as relações entreas tabelas da base de dados, o analista não precisa explicitar estas relações na hora de recuperardados.

Independência da base de dados: definição a nível de atributosA definição dos procedimentos se faz a nível de atributos: não é necessário indicar expl�citamentequais tabelas ser�������� �������� ���� �ndices. Somente mencionando os atributos quedeseja acessar é suficiente para que o GeneXus determine esta informação. Isto é possível porqueGeneXus possui um completo conhecimento da estrutura da base de dados.

Desta maneira obtemos uma real independência da base de dados, já que qualquer alteração nastabelas ser� gerenciado automaticamente pelo GeneXus e desta forma, para atualizar os programasalcança em grande parte das vezes, como regerar os objetos sem ter que modificar nada doprogramado neles.

Page 4: 07 procedures-curso gxxbr

���

Para cada procedimento se pode definir:

• Source: Aqu� �� o c�digo correspondente a l�gica do procedimento. Também podem definir-se ao finaldo c�digo subrotinas1 que podem ser chamadas a partir do próprio código mediante o comando adequado.

• Layout: As �� como as transações possuem uma tela (form), os procedimentos possuem um �layout� de saída.Nesta seção se define apresentação do procedimento: os dados que se quer listar e o formato da saída.

• Regras-Propriedades: Definem aspectos gerais do procedimento, como seu nome, descrição, tipo de saída(impressora, arquivo, tela), parâmetros que recebe o objeto, etc.

• Condições: Condições que devem cumprir os dados para ser recuperados (filtros).

• Variáveis: Variáveis locais ao objeto.

• Ajuda: Permite a inclusão de texto de ajuda, para ser consultado pelos usuários em tempo de execução, para ouso do procedimento. Pode ter uma ajuda para cada linguagem.

• Documentação: Permite a inclusão de texto t�cnico, para ser utilizado como documentação do sistema.

_____________________________________________________________________________________1 Não serão vistas no presente curso. Ver no Curso Não Presencial de GeneXus.

Page 5: 07 procedures-curso gxxbr

���

Por exemplo, vamos supor que queremos implementar um procedimento para imprimir o identificador,nome e pa�s de todos nossos clientes e queremos que a listagem saia como mostrada na figura.

Para isso, devemos identificar na saída da listagem das distintas �reas que o compõem. A cada umadelas a representaremos com um Printblock.

Os primeiros dois Printblocks ilustram no GeneXus tal qual as primeiras duas �reas pois contemunicamente textos, linhas, retângulos. Também poderíamos ter colocado estas duas �reasconvertendo-as em uma e utilizando portanto um �nico Printblock.

O terceiro Printblock ser� o correspondente da �rea de dados variáveis da figura anterior, querepresenta informação que deve ser extra�da da base de dados.O que queremos mostrar neste caso é o identificador e nome de cada cliente, junto com o nome dopa�s ao que pertence. Esta informação é a representada pelos atributos CustomerId, CustomerNamee CountryName da base de conhecimento da aplicação, o terceiro Printblock conter� os três controlesatributo CustomerId, CustomerName e CountryName.

Transformando as �reas em Printblocks, o Layout do procedimento ficará como o da figura na p�ginaseguinte.

Page 6: 07 procedures-curso gxxbr

���

O Layout de um procedimento será uma sucessão de Printblocks que não tem por que seguir aordem em que deseja que apareçam na saída.

No exemplo anterior, o mesmo procedimento teria sido impresso se houvesse especificado osPrintblocks na ordem inversa (ou em qualquer ordem).

Aqui simplesmente são declarados. A ordem que são executados fica determinado na seção Sourceque é a que contem a lógica do procedimento. A partir dali serão chamados mediante um comandoespecífico para tal finalidade (o comando print).

Por esta razão, cada Printblock deve ter um nome único para poder ser referenciado depois a partir doSource.

No exemplo, para listar todos os clientes, o Printblock de nome “customer” deve ser chamado dentrode uma estrutura repetitiva no Source. Esta estrutura repetitiva é o comando For each queestudaremos depois.

Page 7: 07 procedures-curso gxxbr

���

O Printblock é um tipo de controle v�lido somente nos procedimentos, que é inserido e eliminado doLayout pelo analista, e que contem outros controles -atributos, textos, retângulos, linhas, etc.-, sendoestes �ltimos os que efetivamente especificam qu��é o que se quer mostrar na saída.

Para inserir os controles no Form de uma transação contamos com uma toolbox. A mesma toolbox seutiliza para inserir os controles no Layout. De fato esta toolbox está disponível para todos os objetosGeneXus criados, e em cada caso terá os controles disponíveis segundo o tipo de objeto.

Para inserir um Printblock - botão direito em qualquer lugar do layout e selecionamos InsertPrintblock.

Como todo controle, o Printblock possui propriedades que podem ser configuradas pelo usuário. Emparticular, tem a propriedade “Name”, muito importante visto que é o identificador do Printblock. Comeste identificador é que o Printblock pode ser chamado a partir do Source para ser impresso.

Para acessar as propriedades de um Printblock, o selecionamos e pressionamos F4 ouView/Properties.

Page 8: 07 procedures-curso gxxbr

���

Nesta seção se define a lógica do procedimento .

A linguagem utilizada para programar o código fonte dos procedimentos é muito simples, e consta dealguns comandos que veremos.

O estilo de programação é procedural – imperativo – o Source será uma sucessão de comandosonde a ordem é fundamental: a ordem em que estejam especificados corresponderá, excetoexceções, a ordem em que serão executados.

Existem, como em toda linguagem imperativa, comandos de controle para a execução condicional (if,do case), o repetitivo (do while, for), para chamar a outro objeto (call), para cortar as iterações dentrode um loop (exit) ou abandonar o programa (return), assim como também comandos específicosdesta linguagem: para imprimir um Printblock do Layout (print), para acessar a base de dados (Foreach), para inserir novos registros em uma tabela (new), para chamar a uma subrotina (do), etc.

No final da sucessão de comandos que constitui o código geral ou principal do procedimento, podemdefinir-se subrotinas que podem ser chamadas (mediante o comando do) a partir do código geral.Não podem ser chamadas a partir de outro objeto (são locais).

Por sua importância, começamos estudando detalhadamente o comando de acesso a base de dados,fundamental na hora de recuperar a informação armazenada. Depois serão tratados brevemente oscomandos de controle, que são comuns a todos as linguagens de programação imperativa, oscomandos de atribuição e os de impressão.

Page 9: 07 procedures-curso gxxbr

��

A definição do acesso a base de dados para recuperar a informação se realiza com um únicocomando: o comando For each1.

Usando o For each se define a informação que vai acessar. A forma de o fazer é baseada em nomearos atributos a utilizar.

Assim, com este comando se definem quais atributos são necessários em qual ordem vai serrecuperada, e GeneXus se encarrega de encontrar como fazer. Não se especifica de quais tabelas sedevem obter, nem quais índices se devem utilizar para acessar a essas tabelas: isso GeneXus infere.Evidentemente isto nem sempre é possível, e em tais casos GeneXus dá uma série de mensagens deerro indicando por que não se podem relacionar os atributos envolvidos.

A razão pela qual não se faz referencia ao modelo físico de dados é porque desta maneira aespecificação do procedimento é de mais alto nível possível, de tal forma que ante mudanças naestrutura da base de dados a especificação do mesmo se mantenha válida a maior parte das vezes.

Quando aparece um For each se está indicando que se quer recuperar informação da base de dados.Concretamente GeneXus sabe que com um For each se quer percorrer (ou navegar) uma tabela.Para cada registro dessa tabela, se quer fazer algo com a informação associada (ex: imprimir).

Portanto, todo comando For each possui uma tabela física associada: a tabela que será percorrida ounavegada. A esta tabela vamos chamar tabela base do For each.

______________________________________________________________________________1 Quando estudarmos os business components veremos que utilizando seu método Load também seconsegue consultar a base de dados.

Page 10: 07 procedures-curso gxxbr

��

Intuitivamente com este comando queremos listar identificador, nome e país de cada um dos clientesda base de dados. Ou seja, queremos percorrer à tabela CUSTOMER, e para cada cliente sejarecuperado da tabela COUNTRY o nome do país ao qual pertence, imprimindo esta informação, juntocom o identificador e nome do cliente. (Observar que a tabela COUNTRY pertence à estendida deCUSTOMER)

Como o GeneXus infere isto, só o que fizemos foi For each do exemplo informar os atributos que nosinteressava mostrar?

Page 11: 07 procedures-curso gxxbr

���

Dentro de todo For each navega-se - percorre ou itera - a tabela base, mas podemos acessar astabelas que constituem sua tabela estendida para recuperar a informação, por pertencer aestendida está relacionada com cada registro da tabela base com que esteja trabalhando em cadainteração (o conceito de tabela estendida é muito importante neste comando e sugerimos repassarsua definição).

É por isso que no For each do exemplo, a tabela base será CUSTOMER, e acessa “para cada”cliente, não somente os dados de seu registro, como também do registro associado na tabelaCOUNTRY (que está na estendida de CUSTOMER). Dizemos então que se percorre CUSTOMER ese acessa além disso a de COUNTRY para buscar o resto da informação requerida.

Como podemos ver claramente no exemplo apresentado, não apresentamos de forma explícita aoGeneXus esta informação. Não é necessário, já que o GeneXus conhece as relações entre astabelas, e na base os atributos mencionados dentro do For each e pode encontrar sem necessidadede mais informações uma tabela estendida que os contenha.

A tabela base dessa estendida é escolhida como tabela base do For each.

Page 12: 07 procedures-curso gxxbr

���

A tabela base correspondente a essa tabela estendida é chamada de tabela base do For eache será percorrida seqüencialmente, executando para cada registro o que for indicado noscomandos internos do For each.

Page 13: 07 procedures-curso gxxbr

���

Para o exemplo apresentado onde queremos uma lista dos clientes: seu identificar, nome e nome depaís, observamos os atributos utilizados dentro do For each, e percebemos que eles são os contidosno print block de nome “customer”: CustomerId, CustomerName e CountryName.

Em que tabelas estão estes atributos?

• CustomerId est� em 2 tabelas:- CUSTOMER como chave primária (PK).- INVOICE como chave estrangeira (FK).

• CustomerName est� somente em CUSTOMER (é um atributo secundário).

• CountryName est� somente em COUNTRY (é um atributo secundário).

GeneXus conhece as relações entre as tabelas. Podemos ver o diagrama correspondente às tabelasnas quais aparecem os atributos do For each (Tools/Diagrams).

Aqui podemos ver porque do requerimento da tabela estendida seja a mínima (entendendo pormínima aquela que envolve um número menor de tabelas). A tabela estendida de INVOICE tambémcontêm todos os atributos do For each, mas não é mínima, pois a de CUSTOMER também oscontêm.

Portanto, se vamos percorrer seqüencialmente à tabela CUSTOMER, e para cada registro dessatabela, vamos acessar a tabela COUNTRY, e recuperar o registro da mesma que cumpre:COUNTRY.CountryId = CUSTOMER.CountryId e para o mesmo recupera-se o valor do atributoCountryName, para poder imprimi-lo, junto com o código e nome do cliente.

Page 14: 07 procedures-curso gxxbr

���

Listagem de navegação

GeneXus oferece para todos os objetos uma lista conhecida como listagem de navegação, que é oresultado da especificação do objeto. Esta listagem é muito útil para os relatórios, já que indica quaissão as tabelas que são acessadas em cada For each do Source, se existe um índice para recuperaros dados da tabela base, e em caso de que assim seja qual é esse índice (seu nome), se aplicamfiltros sobre os dados ou se devemos listar todos, etc.

Desta maneira, o analista não tem que executar o objeto para verificar se a lógica é a esperada.Estudando a listagem de navegação já têm a informação necessária para saber se está percorrendoa tabela esperada, se estão aplicando corretamente os filtros desejados, etc.

Como pode ser visto, esta listagem mostra para o comando For each que aparece no Source, qual éa tabela base do mesmo, por que ordem essa consulta é resolvida (a ordem que os resultados sãoimpressos), se existe um índice que satisfaça essa ordem, qual é seu nome, e aparecem mais duasinformações envolvidas: os filtros de navegação e o diagrama de tabelas.

Os filtros da navegação indicam que faixa da tabela base que vai ser percorrida. No Exemplo épercorrida toda a tabela base do For each: começando pelo primeiro registro de CUSTOMER, atéque chegue ao fim de tabela (utilizando o índice ICUSTOMER).

Também é mostrado num pequeno diagrama de tabelas, a tabela base do For each com sua chaveprimária, e endentadas todas as tabelas da estendida que devam ser acessadas para recuperar ainformação associada ao registro da tabela base que está sendo trabalhada em cada interação doFor each. Neste caso se mostra somente a tabela COUNTRY.

No comando For each do Exemplo não aparece explicitamente nenhuma informação referente aordem desejada da impressão da informação do relatório. Neste caso GeneXus escolhe a ordem dachave primária da tabela base do For each. É por esta razão que no For each do Exemplo,GeneXus determinou que a ordem é realizado pelo atributo CustomerId, chave primária da tabelaCUSTOMER.

Page 15: 07 procedures-curso gxxbr

���

Para restringir os dados que queremos listar no For each são utilizadas as cláusulas where do comando.

Se na listagem de clientes não queremos listar todos os clientes, mas apenas aqueles cujo nome esteja dentrode uma faixa inserida pelo usuário, então devemos agregar ao For each que havíamos visto uma cláusulawhere, para especificar os filtros desejados sobre os dados:

For eachwhere (CustomerName >= &Start) and (CustomerName <= &End)

print customerEndfor

onde as variáveis &Start e &End devem ser definidas no procedimento com o mesmo tipo de dados queCustomerName, e as carregar com valores fixos ou recebidos por parâmetro1.

Com a cláusula where definida estamos dizendo ao GeneXus que não queremos todos os registros da tabelabase, e sim, somente aqueles que satisfaçam a condição booleana da cláusula.

No exemplo escrevemos uma cláusula somente where com uma condição composta, mas poderíamos terprogramando o mesmo com duas cláusulas where, como mostramos no slide acima.

Quando aparecem vários “where” a condição de filtro que vai ser aplicada sobre os dados é a conjunçãobooleana de todas as Condições dos “where” que apareceram.

Observemos que no slide os comandos where estejam condicionadas com as claúsulas when. Se interpreta daseguinte forma: os filtros estabelecidos pelo where são aplicados somente quando o when é satisfeito. Isto é lidoda seguinte forma: o filtro estabelecido será aplicado pelo where somente quando satisfaça a condição do when.

No exemplo, somente é aplicado o primeiro filtro: “CustomerName >= &Start” se a variável &Start não for vazia.Se for vazia, este filtro não será aplicado. Igual é ao caso da segunda cláusula when. Observar que se &Start e&End estejam vazios, não serão aplicados nenhum dos comandos where, e portanto serão listados todos osclientes (como se não existissem os comandos where).

Cada condição booleana de um “where” pode estar composta de várias expressões booleanas concatenadascom os operadores lógicos and, or e not._____________________________________________________________________________________1 A través de um objeto que é pedido ao usuário, por exemplo um Web Panel.

Page 16: 07 procedures-curso gxxbr

���

Listagem de navegação

Aparece um novo elemento nesta listagem que não existia, quando não tínhamos cláusulas where: osconstraints (restrições).

Que informação ganhamos com esta listagem de navegação?

• que a tabela base do For each continua sendo CUSTOMER

• que a ordem da consulta continua sendo por CustomerId, utilizando o índice ICUSTOMERcorrespondente

• que continua percorrendo toda a tabela CUSTOMER em busca da informação

• mas para cada cliente avalia se cumpre as restrições que aparecem enumeradas(CustomerName>= &Start se &Start não estiver vazia e CustomerName<=&End se &End não estivervazio) e somente caso se cumpra, executar para esse cliente os comandos que aparecem dentro doFor each. Neste caso, imprime os valores dos atributos do Printblock “customer”: CustomerId,CustomerName, CountryName.

• que deve acessar a tabela COUNTRY cuja chave primária é CountryId para obter algum dado(CountryName)

Page 17: 07 procedures-curso gxxbr

���

Os atributos utilizados nas condições de filtro podem ser de qualquer tabela estendida do For each.

No exemplo, a tabela base do For each é CUSTOMER, estamos filtrando os dados a seremrecuperados utilizando o atributo CountryName, que é da tabela COUNTRY, pertencente à tabelaestendida de CUSTOMER.

Neste exemplo nada foi feito em relação à ordem, os dados aparecerão ordenados pela chaveprimária da tabela base, ou seja, pelo identificador de cliente, CustomerId..

Page 18: 07 procedures-curso gxxbr

���

Se queremos realizar uma lista de todos os clientes, ordenado por nome do cliente ao invés docódigo, precisamos modificar o comando For each agregando esta informação da ordem.

Fazemos isso utilizando a cláusula order do For each, como mostramos no primeiro exemplo.

Como não existe um índice definido na tabela CUSTOMER por atributo CustomerName, o GeneXusindicará na listagem de navegação mediante uma advertência (“warning”) que não existe um índicepara satisfazer a ordem, o que pode ocasionar problemas de performance, dependendo daplataforma de implementação, da quantidade de registros que devem ser lidos da tabela, etc.

Em ambientes cliente/servidor, se não existe índice para satisfazer a ordem, o For each se traduznuma consulta SQL (“select”) que é resolvida pelo motor do DBMS da plataforma.

Igual o caso dos comandos where, em plataformas cliente/servidor a cláusula order pode sercondicional, como o exemplo dois.Caso a condição when não for cumprida, essa ordem não será utilizada e não existir ordemincondicional (sem a cláusula when) como no exemplo, a ordem será indefinida, isto é, a ordempoderá variar de DBMS a DBMS e inclusive entre execuções seguidas.

Podem ter várias cláusulas order consecutivas condicionais (com cláusula when) em arquiteturascliente/servidor e uma sem condição (a última da lista). O primeiro comando order cuja condição dowhen for satisfeita, será a ordem escolhida para ser utilizada.

Clásula Order None: clásula que evita que GeneXus escolha por default a ordem dos atributos dachave primária da tabela base e utiliza uma ordem de navegação indefinida.Se utilizar a cláusula Order None, GeneXus entende que não deseja estabelecer nenhuma ordemem particular e delega esta tarefa ao DBMS.A cláusula order none pode ter condição (when).

Page 19: 07 procedures-curso gxxbr

��

Listagem de navegação

Quando não existe um índice que satisfaça o ordem de um For each, como é o caso do Exemplo, oanalista GeneXus pode resolver criá-lo (índice de usuário). Na maioria dos casos o relatório serámais eficiente desta maneira, mas o índice é mantido (implicando num maior armazenamento e maiorprocessamento para que o índice seja mantido atualizado)

Não é possível recomendar a priori qual das duas soluções é a melhor (índice temporário vs índice deusuário), portanto deve-se estudar, caso por caso, a solução particular levando em consideração aplataforma de implementação e sendo fundamental a analisar a freqüência que o relatório éexecutado. De qualquer maneira, se no início não foi definido o índice de usuário e posteriormentedecide-se fazê-lo, somente é preciso que o relatório seja gerado novamente (sem modificar nada doque foi programado) e o relatório passará a utilizá-lo.

A listagem de navegação anterior mostra o seguinte:

• a tabela base do For each é CUSTOMER• a ordem é por CustomerName• não existe um índice definido para esse atributo• toda a tabela CUSTOMER com a ordem especificada será recorrida• não tem condições de filtro, todos os registros da tabela executarão os comandos dentro do Foreach (neste caso, o comando print)

Page 20: 07 procedures-curso gxxbr

��

Se queremos filtrar os clientes por determinada faixa de nomes, o primeiro exemplo, como não foiespecificada a cláusula order, GeneXus ordena pela chave primária, ou seja, CustomerId.

Neste caso, a listagem de navegação mostra que deve-se percorrer toda a tabela CUSTOMER, epara cada registro da mesma deve-se analisar se o registro cumpre ou não as condições (restriçõesou “constraints”). Em caso afirmativo, será impresso o mesmo os dados correspondentes.

Ao invés de ordenar os dados por CustomerId vamos fazer uma ordenação por CustomerName,como no segundo exemplo, a tabela base é percorrida ordenada por CustomerName e como nosfiltros estabelecemos que queremos somente aqueles clientes cujo nome, CustomerName, esteja nafaixa determinada, já não sendo necessário recorrer toda a tabela base para obter os dados quecumprem com as Condições!

A segunda consulta está otimizada nesse sentido. Prestar atenção que o GeneXus não criou umíndice por CustomerName de forma automática, e aqui temos que avaliar se é conveniente criar umíndice de usuário (será mantido pelo GeneXus depois de criado) ou não criar o índice e deixar queseja criado um índice temporário em execução para resolver a consulta se o DBMS não pode fazerde outra forma.

A listagem de navegação mostra se a consulta está ou não otimizada, de acordo se toda a tabela épercorrida (desde “First Record” até “End of table”) ou apenas uma faixa mais reduzida

Page 21: 07 procedures-curso gxxbr

���

A listagem de navegação nos informa que a consulta está otimizada já que percorre somente osregistros incluídos no filtro (desde CustomerName>=&Start até CustomerName <=&End).

Para determinar a ordem levar em consideração:

• Os atributos da cláusula Order especificada pelo usuário• As restrições que aplicam ao nível (atributos mencionados na regra Parm do procedimento,condições explícitas tanto no Where como nas Conditions)• A existência de índices sobre estes atributos.

Distinguimos 2 casos:

1) Se escreve uma cláusula order

•O For each fica ordenado por esses atributos, exista ou não um índice por estes.•Se não existe um índice com os atributos do order, mas existem condições implícitas oucondições explícitas por igualdade, se busca se existe um índice que contenha os atributosdas condições mais os do Order. A condição explícita prevalece sobre a implícita para adeterminação do Order, em caso que sejam diferentes e exista índice por cada uma delas.•Se existe um índice, os atributos das condições serão agregadas na lista do Order para quedito índice seja considerado em seu lugar.

2) Não se escreve cláusula order

•Neste caso, se existe algum índice para os atributos da condição, o Order fica determinadopelos atributos do índice.•Se não existe um índice que corresponda com as condições, ou seja que não se podeotimizar a percorrida segundo as condições do nível, então se ordena pelos atributos daPrimary Key.

Page 22: 07 procedures-curso gxxbr

���

Por exemplo, se temos as transações:

COUNTRY CITY{ {

CountryId* CountryId*} CityId*

}

O For each:

For Each order CityIdWhere CountryId = 1

...Endfor

Percorre a tabela CITY, ordenando por: CountryId, CityId e utilizando o índice ICITY (índice por chaveprimária que contem ambos atributos).

Ainda é o próprio DBMS que resolve o plano de acesso mais apropriado, a informação antesmencionada influirá em sua determinação.

Page 23: 07 procedures-curso gxxbr

���

Pode ocorrer de que um For each tenha mais de uma tabela base cuja estendida contenha os atributos do Foreach, sendo mínima. Frente esta ambigüidade, GeneXus escolhe a “primeira” destas tabelas estendidasmínimas.

Para resolver este tipo de ambigüidade surge a cláusula defined by, que permite usar atributos da tabela basedesejada, que não serão utilizados para devolver a consulta ordenada por esses atributos, nem para filtrarinformação, nem para ser mostrados no relatório (não tem nenhuma funcionalidade com respeito aos dados àrecuperar), apenas para aportar mais informação que permita determinar a tabela base do for each.

Na cláusula Defined by devemos fazer referência pelo menos à um atributo da tabela base desejada.

Da mesma forma, pode ser utilizada para modificar qual é a tabela base em caso de não utilizar nenhum atributomais dentro do For each. Este é o caso do exemplo apresentado, não que não queremos listar todos os clientesda tabela CUSTOMER, pelo contrário, queremos listar todos os clientes das faturas. Se não utilizar nenhumatributo dentro do For each de INVOICE , a tabela base é a de CUSTOMER.

Na maioria dos casos não é necessário utilizar este comando. Para procedimentos mais ou menos complexos,quando não exista problema de ambigüidade, recomenda-se o uso do Defined by pois melhora bastante o tempode especificação do procedimento.Contudo, não é aconselhável seu uso indiscriminado. A desvantagem de utilizar esta cláusula quando não énecessário é que “ata” um pouco mais o código ao desenho das tabelas.

Por exemplo, não foi criada uma tabela COUNTRY, e para cada cliente o país que ele pertence, como atributosecundário. Se quisermos uma listagem dos clientes e seu país, seriam equivalentes:

For each For eachDefined by CountryName

print customer print customerEndfor Endfor

onde customer é um Printblock com os atributos CustomerId, CustomerName e CountryName.Se agora decidir criar a tabela COUNTRY e ter na transação “Customer” a CountryId como FK, o primeiro Foreach continuará sendo válido e fazendo o que queremos, o segundo deixará de funcionar, ja que no Defined Bynão tem nenhum atributo da tabela base.

Page 24: 07 procedures-curso gxxbr

���

Podem aparecer vários atributos, no caso de um único atributo não determinar a tabela base, ondeao menos um deles deverá estar associado à tabela base desejada.

Recomenda o uso do defined by de atributos secundários da tabela base que desejamos navegar,já que os atributos secundários somente podem estar em uma tabela do modelo e desta formaeliminamos por completo toda possível ambigüidade.

Isto não é obrigatório, podemos usar no Defined by para atributos primários quando notarmos quenão haverá ambigüidade na eleição da tabela base.

Um erro comum é acreditar que quando um For each tem esta cláusula, a tabela base do mesmo ficadeterminada exclusivamente a partir dos atributos mencionados no defined by.

A realidade é que os atributos do defined by determinam uma ou mais tabelas base candidatas aserem a tabela base do For each, mas tendo selecionado a tabela base candidata, sua estendidacontêm todos os demais atributos do For each, além dos do defined by.

Se nenhuma das possíveis tabelas base candidatas cumprem esta condição, então o relatório daráum erro ao ser especificado, e não poderá ser gerado (recordemos que todos os atributos do Foreach devem estar contidos em uma mesma tabela estendida).

Page 25: 07 procedures-curso gxxbr

���

O Printblock menssage (poderá ter um texto advertindo ao usuário que não existam clientes quecumpram os filtros) executa somente quando não entrar no For each, isto é, quando não tem nenhumregistro correspondente na tabela base do For each para que se cumpram as Condições de filtro

Também aplica-se o For each [selected] line, XFor Each y XFor First, comandos que veremos maisadiante.

A cláusula when none deve ser a última dentro do For each. As ações a serem realizadas quandonão existe nenhum registro que cumpra as condições, ficam determinadas pelo bloque de código quetem dentro cláusula when none do For each e do endfor.

Quando um For each não tem condições de filtro, os comandos do When none serão executadossomente no caso em que a tabela base do For each esteja vazia, porque somente nesse caso nãohaverá nenhum registro que cumpra as condições de filtro.

Importante:

•Se aparecer atributos no bloque de código correspondente ao When none, estes não são levadosem consideração para determinar a tabela base do For each.

• Se incluir For eachs dentro do When none não se inferem Joins nem filtros de nenhum tipo comrespeito ao For each que contêm o When none, já que são considerados dos For eachs paralelos.

Page 26: 07 procedures-curso gxxbr

���

A Sintaxe apresentada generaliza o exemplo com o que estamos trabalhando.

Order order_attributes::= att1, …, attnÉ uma lista de atributos, que indica a ordem da consulta, sendo atti um atributo da base deconhecimento escrito simples, ou entre parênteses. Quando um atributo do order aparece entreparênteses está indicando a ordem descendente para o mesmo.

Podem se mencionar atributos da tabela estendida.

É possível definir várias cláusulas order condicionais, e uma incondicional, que deveria ser a últimalistada. Respondendo ao fato de que somente uma dessas cláusulas order tomará efeito, se vãoavaliando suas condições (as do when) até a primeira que de True, e com essa fica. Se nenhumader true e existe uma cláusula incondicional (isto é, sem when), pega essa ordem. Se não existe talcláusula, ou ordem será indefinido, querendo isto significa que dependerá da plataforma, e inclusopoderá variar entre execuções sucessivas. A justificatova para escrever cláusulas ordercondicionais, deriva se quisermos aplicar cláusulas where condicionais. Isto é, por motivos deotimização das consultas.

Por exemplo, se queremos filtrar por CustomerName > &Name when not &Name.IsEmpty(), entãopara otimizar a consulta deveríamos ordenar por CustomerName, mas se não aplicar o filtro, vistoque &Name está vazio, então será melhor deixar uma ordem indefinida.Para isso especificamos a cláusula order condicional:

order CustomerName when not &Name.IsEmpty()

Ao invés do exemplo anterior, também pode ser especificado uma cláusula order none que éutilizada quando não nos interessa uma ordem em particular e queremos que fique indefinido.

Page 27: 07 procedures-curso gxxbr

���

Escolha do índice: GeneXus escolhe automaticamente o índice que utilizará para satisfazer a ordem. GeneXus sempre tentaráencontrar a melhor ordem possível para que a consulta seja otimizável, isto é, coincida com algum índice definido na base dedados. Para determinar a ordem é levado em consideração:

•Os atributos da cláusula Order especificada pelo usuário•As restrições que aplicam ao nível (atributos mencionados na regra Parm do procedimento, condições explícitas tanto no Wherecomo nas Conditions)•A existência de índices sobre estes atributos.

Ainda é o próprio DBMS que resolve o plano de acesso mais apropriado, a informação antes mencionada influirá em suadeterminação.

Os atributos do order são levados em consideração na hora de determinar a tabela base do For each. Mas eles por si só nãodeterminam. Devem examinar-se também outras partes do For each.

Using DataSelectorNamePermite definir filtros de acordo ao critério definido no DataSelector1 definido em DataSelectorName.

Where ConditionCondição booleana que deverão cumprir os dados para ser processados dentro do For each, podendo ser uma condiçãocomposta, utilizando os operadores l�gicos and, or e not.

Os atributos que apareçam na condição booleana podem ser tanto da tabela base do For each como da estendida.

Como se desprende da sintaxe, para um mesmo For each podem especificar-se n cl�usulas where sucessivas, cada uma comuma condição:where cond1where cond2...where condn

A ocorrência de n cl�usulas where é equivalente a ocorrência de uma única cl�usula, com a conjunção booleana das condições:

where cond1 and cond2 and and condn

Os dados da tabela estendida do For each que cumpram com todas as condições dos �where� ser��os processados noscomandos internos ao For each (os do bloque de c�digo code1).

Da mesma forma que ocorre com a cl�usula order, pode condicionar os filtros (com cl�usulas when). Desta maneira, primeiro seavalia a cl�usula when de cada cl�usula where, e caso a condição seja cumprida, aplicam o filtro especificado no where.

Para que uma restrição condicional possa ser gerada como tal, a condição do when tem que ser “avaliável" pelo DBMS que seestá utilizando, isto é, GeneXus tem que saber como escrever a condição na linguagem própria do DBMS utilizado.

Se não puder gerar como tal (porque o gerador não o suporta ou porque a condição não pode ser escrita na linguagem doDBMS) se transformará em um filtro "comum" substituindo o WHEN por um OR. Além disso, se gerar a mensagem de códigospc0053 – ‘Unsupported conditional constraint”%1” changed to standard constraint %2.’ - no Diagrama de Navegação.

Nota: Existe também a cl�usula Option Distinct do For Each que permite retornar os registros que cumpram unicidade devalores dos atributos referenciados. Não veremos esta cláusula. O leitor interessado pode recorrer as distintas fontes dedocumentação para estudá-la (Help, Wiki, Release Notes, etc.)

Defined bydefined_attributes::= att1, att2,…,attpÉ um conjunto de atributos que serão utilizados somente efeitos de determinar a tabela base do For each.

Ao mencionar aqui alguns atributos da tabela que se deseja percorrer, estes participarão na determinação da tabela base do Foreach.

A cláusula defined by aparece para solucionar alguns problemas de ambigüidade na determinação da tabela base (quandoexistem várias tabelas estendidas mínimas que contenham os atributos do For each) ou quando se deseja que a tabela base sejaoutra, diferente da que seria determinada pelos atributos que aparecem no resto do For each (este caso tem sentido quando seestude “controle de corte”). Também se utiliza para melhorar o tempo de especificação em procedimentos complexos.

Os atributos desta cláusula não determinam por si só a tabela base do For each. Poderia acontecer que estes atributosdeterminam tabela como a candidata a tabela base, mas se depois os outros atributos do For each não estão contido naestendida dessa tabela, o For each dará um error e o objeto que o contem não poderá ser gerado.

code1É uma sucessão de comandos que podem utilizar atributos da tabela estendida do For each. A este bloque de código ochamaremos corpo do For each.

Os atributos que figurem neste bloque de código participam na determinação da tabela base do For each.

_________________________________________________________________________________________________1 O objeto DataSelector será visto mais adiante no curso.

Page 28: 07 procedures-curso gxxbr

���

Os comandos especificados serão executados seqüencialmente para os dados da tabela estendida que cumpramas Condições de filtro, considerando os dados na ordem especificado.

BlockingEste tema será abordado mais adiante do curso, mas a idéia geral é que a especificação desta clásula permiterealizar atualizações e eliminações em blocos, reduzindo assim o número de acesso a base de dados.

When DuplicateEsta cláusula tem sentido somente em procedimentos (já que trata de atualização) e será visto mais adiante.Esta cláusula é executada se dentro do corpo do For each code1, atualizar um atributo que é chave candidata(possui índice único) e já existir um registro com esse valor. GeneXus utiliza o índice único para assegurar aunicidade dessa chave candidata e caso encontre duplicação, se o For each tem essa cláusula programada,executará seu código: code2.Não existindo a cláusula nenhum código será executado.

When noneEm caso de que não existam dados que cumpram as Condições de filtro não será executado os comandos docode1 e sim os bloque de código code3.

� Tanto para When Duplicate como para When none: incluindo um comando For each dentro dentro de um dosdois, não são inferidos nem joins nem filtros com respeito ao For each que o contêm (when none|when duplicate).São considerados navegações independentes (code1, code2 e code3).

Page 29: 07 procedures-curso gxxbr

��

Os �code snippets� são moldes de c�digo que GeneXus tem predefinido, que nos ajudam aescrever o c�digo fonte. Quando estamos trabalhando no Source de um procedimento, aToolbox nos mostra vários snippets que nos facilitam a escrita do comando For each.

Os snippets possui por sua vez um �atalho� (shorcut), que fazem que a escrita do c�digo sejamais r�pida todav�a. Por exemplo, digitando simplesmente �fe� se escreve autom��icamente oseguinte c�digo:

For each/*For each Code*/

Endfor

Depois o usuário substitui a linha de comentários com o c�digo necessário.

A lista dos atalhos de cada snippet, é a seguinte:

• fe (For each)• feu (For each using)• fen (For each When none)• feun (For each using When none)• few (For each where)• feuw (For each using where)• fewn (For each where When none)• feuwn (For each using where When none)

Page 30: 07 procedures-curso gxxbr

��

O For each é um comando como outros, e portanto pode aparecer várias vezes dentro do Source,tanto em forma paralela (independente), como aninhado a outro For each.

Quando dentro do corpo do For each (code1) aparece outro For each, dizemos que trata-se de Foreachs aninhados. GeneXus suporta vários níveis de aninhamento para os For eachs.

Se um For each aparece no bloque de código code3, pode ser visto como For eachs aninhadosporque um aparece dentro de outro, muda o comportamento, é igual a ter For eachs paralelos.

Um For each “aninhado no when none” de outro, somente é executado se não tem nenhum registroda tabela base do For each que o contêm que cumpra as condições de filtro.

No exemplo, “invoices” e “bill” são dois Printblocks do Layout que contêm os atributos das tabelasINVOICE e BILL (recibo) respectivamente.

Temos definido dois For eachs paralelos. O primeiro percorre todas as faturas e o segundo todos osrecibos.

Page 31: 07 procedures-curso gxxbr

���

O For each é uma estrutura repetitiva, que permite recuperar muitos registros de uma tabela. Quandopensamos em For eachs aninhados, é evidente que o que buscamos recuperar é, para cada registro doprincipal, muitos registros do aninhado.

O que o GeneXus detecta que se quer fazer com este tipo de estruturas, de forma de inferir ocomportamento automaticamente com o menor codificação possível?

• para cada registro de uma tabela recuperar alguns de outra: os relacionados.• para cada registro de uma tabela recuperar todos de outra.• processar informação por grupos, isto é, agrupar os registros de uma tabela segundo o valor de umatributo ou conjunto de atributos e para cada grupo, recuperar alguns registros: os correspondentes aogrupo.

Sempre a relação é um a muitos: para cada registro de uma tabela recuperar muitos da outra (podendo-se tratar da mesma tabela).

Utilizando esta lógica é que o GeneXus infere as tabelas base e o comportamento dos For eachsaninhados, sabendo que o que desejamos é implementar alguma das três opções anteriores.

Por exemplo, se queremos elaborar uma lista de todas as faturas do sistema, sendo que imprimiremosdetalhe de cada uma, devemos navegar por duas tabelas: INVOICE (que armazena os cabeçalhos) eINVOICEDETAIL (que armazena as linhas), e o faremos de uma forma bem simples, sem colocar onome das tabelas, e sem que explicar tudo, como veremos.

Outro Exemplo é de uma lista de todos os clientes, onde para cada um se quer imprimir, além de seusdados pessoais, os dados de todas suas faturas. Este comportamento se dá com um par de For eachsaninhados, onde o primeiro navega pela tabela CUSTOMER e o segundo navega pela tabela INVOICE,recuperando somente as faturas desse cliente, como veremos em seguida.

Page 32: 07 procedures-curso gxxbr

���

Se queremos realizar uma lista de todas as faturas do sistema, onde para cada uma se mostre tantoa informação do cabeçalho como das linhas.

No Source programado, percorremos à tabela INVOICE, imprimindo os atributos que nos interessamdo cabeçalho e para cada registro dessa tabela, percorremos a tabela INVOICEDETAIL, paraimprimir os atributos que nos interessam de suas linhas.

Podemos perceber o quão simples é esse processo, simplesmente utilizando os atributos quequeremos usar, ficando o GeneXus encarregado do resto.

Observemos que nem sequer tivemos que especificar a condição de filtro sobre os registros deINVOICEDETAIL a recuperar. O GeneXus se dá conta da relação existente entre as tabelas, e aplicaautomaticamente a condição de filtro sobre os dados, de maneira que só sejam impressas as linhas“dessa” fatura (lembrar que algo idêntico acontece com as fórmulas verticais, como InvoiceAmount,onde a condição de filtro sobre os registros a serem somados ou contados ficava implícita, e nãoprecisa que especificá-la).

Page 33: 07 procedures-curso gxxbr

���

Como para um For each simples, o GeneXus deve determinar para cada For each (principal eaninhado) qual é sua tabela base. E a partir dessa determinação, utilizará a lógica correspondente.

Mais adiante veremos com exatidão como é que o GeneXus determina cada tabela base. Aquificaremos com idéia intuitiva de que o faz de forma similar como o fazia no caso de um For eachsimples.

Encontra, pois, que deve percorrer as tabelas INVOICE e INVOICEDETAIL.

Como essas tabelas estão relacionadas de acordo a uma relação 1-N infere mais que isso: inferetambém na aplicação da condição sobre os dados de INVOICEDETAIL que indicamos acima.

Page 34: 07 procedures-curso gxxbr

���

Quando temos dois For eachs aninhados,GeneXus deve determinar a tabela base de cada um, eessas serão as tabelas que se navegarão.

Para cada registro da tabela base do For each principal, serão executados os comandos do corpo domesmo. Entre esses comandos, encontra-se o For each interno, que será executado, como qualqueroutro comando, no lugar onde estiver realizando uma navegação sobre sua tabela base.

Para a determinação da tabela base do For each aninhado, influencia a tabela base do For eachprincipal, mas as determinações não são por completo independentes, como se pode pensarequivocadamente.

A partir da determinação das tabelas base de cada For each e das relações que encontre oGeneXus entre as tabelas envolvidas, surgem três possíveis casos de For eachs aninhados, quecorrespondem aos casos enunciados anteriormente: join, Produto cartesiano e corte de controle,respectivamente.

Estudaremos cada um desses casos com exemplos.

Page 35: 07 procedures-curso gxxbr

���

Consideremos o caso mais simples, de um par de For eachs aninhados.

• A determinação da tabela base do For each principal, é análoga ao caso de For each simples(sem aninhamentos). Neste caso consideram-se todos os atributos do For each principal,descartando os For eachs aninhados que este contenha (e todos seus atributos). GeneXus encontraa mínima tabela estendida que os contenha e define assim a tabela base através da qual chega atodas as outras.

• Para determinar da tabela base do for each aninhado, GeneXus fixa os atributos utilizadosdentro do corpo do mesmo, onde estão incluídos ou dentro da tabela estendida previamentedeterminada (a do For each principal). Em caso afirmativo, GeneXus determina que a tabela base doFor each aninhado será a mesma que a do For each principal.Em caso contrário, busca-se a mínima tabela estendida que cumpra e contenha todos os atributos doFor each aninhado e que tenha alguma relação com a tabela base do For each principal. A tabelabase de dita tabela estendida, será a tabela base do For each.

Se não puder encontrar uma tabela estendida mínima que cumpra ambas condições, mas cumpreque contenha os atributos, finalmente a escolhe, mas sempre busca a forma de encontrar relaçõesentre ambas tabelas bases. Somente neste último caso de não se encontrar relações, se procede adeterminar a tabela base como se fosse For eachs independentes.

Estudaremos um esquema resumindo o anterior depois.

Page 36: 07 procedures-curso gxxbr

���

Para o exemplo apresentado anteriormente, mostramos acima como se determina cada tabela base.

Para a do aninhado, como os atributos que figuram não estejam contidos na tabela estendida deINVOICE (que é a tabela base do principal), então se passa a determinar sua tabela base como seexplicou anteriormente: se busca a tabela estendida mínima que contenha a ProductDescription,ProductPrice, InvoiceLineQuantity e InvoiceLineAmount, e caso possível esteja reacionada comINVOICE.

A tabela que cumpre ambos requisitos em INVOICEDETAIL.

Page 37: 07 procedures-curso gxxbr

���

Da determinação das tabelas base, surgem os três casos de For eachs aninhados que forammencionados e que estudaremos um a um em seguida.

Este tema é de vital importância, já que a maioria das aplicações requerem navegaçõescomplexas sobre as tabelas, onde se requer uma mistura de todos estes casos.

Page 38: 07 procedures-curso gxxbr

���

Este é o caso em que o GeneXus determina que as tabelas base de cada For each são distintas e temuma espécie de relação 1-N (podendo ser esta indireta) entre as tabelas que se percorre

Ou seja, para cada registro da tabela base do For each principal, GeneXus encontra que tem Nrelacionados com ele, direta ou indiretamente, na tabela base do For each aninhado.

Ao encontrar esta relação, aplicará condições de filtro automáticas no For each aninhado, de forma aficar somente com esses registros relacionados.

O exemplo do procedimento que imprime todas as faturas do sistema, com seus detalhes, cai dentrodesta categoria. Nesse caso tem uma relação 1-N direta entre as tabelas que se percorre: para cadacabeçalho da fatura, lista-se o mesmo, junto com todas suas linhas da fatura, ou seja, todos osregistros de INVOICEDETAIL que estão relacionados com o registro de INVOICE que se estáposicionado em cada interação.

Este é um dos casos mais comuns de For eachs aninhados, onde se quer percorrer uma tabela, e paracada registro da mesma, percorrer outra tabela, relacionada com a primeira por uma relação N-1. OGeneXus encontra nesta relação, e na navegação interna, somente recupera os registros associados,e aí o nome “join” para este caso.

No exemplo apresentado acima ocorre o mesmo. A tabela base do primeiro For each é CUSTOMER, ea do segundo, INVOICE. Como encontra atributo em comum entre a tabela estendida do For eachprincipal e a tabela base do aninhado1, CustomerId, determina que esse atributo atue comocondição de filtro na percorrida da tabela do For each aninhado.

------------------------------------------------------------------------------------------------------------1 Esta é uma forma de expressar formalmente o que havíamos dito em términos informais: relaçãodireta ou indireta 1-N entre as tabelas base. A relação será direta quando a tabela base do principaltenha relação 1-N com a tabela base do aninhado, isto é, seja superordinada desta última. A relaçãoserá indireta quando isto não exista uma relação direta entre as tabelas base, mas sim entre a tabelaestendida do primeiro e a tabela base do segundo. Também será indireta quando a tabela estendida doaninhado inclua a tabela base do principal. Veremos exemplos em seguida.

Page 39: 07 procedures-curso gxxbr

��

Vejamos, como o GeneXus faz para determinar as tabelas base. Os atributos utilizados no For eachexterno são CustomerId e CustomerName, e a tabela base deste For each será CUSTOMER.Observemos que somente participam na determinação desta tabela base os atributos do For eachprincipal, não os do aninhado.

Depois, GeneXus deve encontrar a tabela base do For each aninhado. Os atributos que participamsão InvoiceId, InvoiceDate e InvoiceAmount, ou seja, os atributos internos a este For each.Observemos que estes atributos não pertencem a tabela estendida do principal, que eraCUSTOMER. Portanto passa a determinar sua tabela base como a de qualquer For each simples: atabela estendida INVOICE contem todos os atributos do For each aninhado, e é a mínima tabelaestendida que os contenha. Portanto, INVOICE será escolhida como tabela base do segundo Foreach.

Observemos, novamente, que não explicitamos cláusula where no For each aninhado para filtrar asfaturas do cliente do For each principal. Justamente, por tratar-se de tabelas relacionadas por umarelação 1-N direta, esta condição é aplicada implicitamente pelo GeneXus e pode ser visto nalistagem de navegação acima.

Outro fato interessante que pode ser observado nesta lista: no For each aninhado não foiespecificado a cláusula order, GeneXus não escolheu a ordem da chave primária da tabela base esim pelo atributo da relação, CustomerId. Desta maneira, está otimizando automaticamente aconsulta.

Esse caso é uma exceção a regra que fala que quando nenhuma cláusula order em um For each éespecificada, GeneXus determina como ordem o atributo da chave primária da tabela base de ditoFor each.

Page 40: 07 procedures-curso gxxbr

��

Se queremos realizar uma listagem das faturas emitidas pelo país, teremos outro caso de For eachsaninhados com distintas tabelas base, onde a informação que queremos listar está relacionada.

Aqui queremos percorrer às tabelas COUNTRY e INVOICE.

Observemos que elas não estão relacionadas diretamente, mas estão de forma indireta. De fato,COUNTRY pertencem à tabela estendida de INVOICE. Portanto, para cada fatura pode-se encontrarsomente um país relacionado à mesma.

Este é um caso um pouco mais complexo que o anterior, porque a tabela estendida do For eachprincipal não tem intersecção com a tabela base do aninhado (est(COUNTRY) ∩ INVOICE = φ), masexiste uma relação 1-N indireta, e o GeneXus a encontra.

Neste caso, a tabela base do For each principal está incluída na estendida do aninhado(COUNTRY ⊂ est(INVOICE)), mas tem uma relação 1-N indireta.

Por este motivo, não necessitamos especificar cláusula where no For each interno para filtrar asfaturas do país do For each principal.

Isto pode ser visto claramente na listagem de navegação, que mostrará o filtro:“CountryId = CountryId” para o segundo For each, mas desta vez como ‘Constraint’ visto que nãopode otimizar a percorrida.

O leitor pode testar este caso em GeneXus e estudar detalhadamente a listagem de navegaçãoresultante.

Page 41: 07 procedures-curso gxxbr

���

Neste caso o GeneXus não encontra uma relação 1-N direta ou indireta entre as tabelas e portantonão aplica filtros implícitos aos registros do For each aninhado, ou seja, realiza um produto cartesianoentre as tabelas.

O caso ocorre quando:• est(For each principal) ∩ base(For each aninhado) = φ e• base(For each principal) ⊄ est(For each aninhado)

Para cada registro da tabela base do For each principal se recorre toda a tabela base do For eachaninhado.

Por exemplo, se a tabela base de um For each foi COUNTRY e a do aninhado PRODUCT,evidentemente não existirá relação e haverá um produto cartesiano e se percorre para cada país,todos os produtos.

O programador pode estabelecer filtros sobre os dados a recuperar, mas estes já não serãocondições implícitas inferidas pelo GeneXus, mas sim especificadas explicitamente peloprogramador..

Page 42: 07 procedures-curso gxxbr

���

No exemplo que vimos anteriormente, da listagem de clientes e suas faturas, o que acontece se umcliente não possuir faturas?

Como a tabela base do For each principal é CUSTOMER, o cliente sai impresso antes de saber-se setem ou não faturas.

Se não desejamos que isto ocorra, isto é, que apareçam listados clientes que não tenham faturas,então a solução é acessar unicamente as faturas, pois se um cliente está nesta tabela, é porqueestá em uma fatura!.

Mas para poder agrupar as faturas por cliente, de tal forma de poder mostrá-las desse modo, devemospercorrer a tabela INVOICE ordenada por CustomerId. Desta forma processaremos a informação deum cliente, e depois passaremos ao seguinte, para processar sua informação, e assimsucessivamente.

Se imaginamos um ponteiro que se vai mostrando sequencialmente pela tabela INVOICE, podemosescrever o pseudocódigo de nosso procedimento como segue:

1. Para o registro apontado, reter o valor do atributo de corte ou agrupamento, CustomerId.

2. Acessar a tabela CUSTOMER (que está na estendida de INVOICE) para recuperar oCustomerName e imprimi-lo junto com o CustomerId (“print customer”)

3. Enquanto o valor de CustomerId do registro apontado coincida com o valor retido no passo 1(aqui se processam todas as faturas do cliente)

a. Imprimir InvoiceId, InvoiceDate e InvoiceAmount do registro apontado.(“print invoice”)

b. Avançar o ponteiro ao seguinte registro e voltar ao passo 3.

4. Voltar ao passo 1. (quando se chega a este ponto, é porque se chegou no final da tabela ou mudouo cliente).

Page 43: 07 procedures-curso gxxbr

���

GeneXus oferece uma forma de programar o que foi visto de uma forma simples.

O pseudocódigo visto na página anterior se programa em GeneXus com um par de For eachsaninhados que estão no slide acima.

Comparando este código com o que vimos anteriormente para o caso de join, vemos que existemsomente duas diferenças: a cláusula order que aparece neste código, junto com o defined by. Somentecom essas mudanças da lista original, mudamos radicalmente o comportamento, neste caso somenteserão listados os clientes que possuem faturas.

Neste caso, ambas cláusulas (order e defined by) são indispensáveis para que este relatório funcionecomo queremos. Se agregamos somente uma delas, o resultado é outro.

Não é em toda programação de controle de corte que deverá ter uma cláusula defined by no For eachprincipal, mas sim uma cláusula order.

A cláusula order é indispensável, porque é ela que especifica por qual atributo ou conjunto deatributos o corte (ou agrupamento) será realizado. Isto é, especifica essa informação comum ao grupo,que será processada uma única vez (dentro do código do For each externo).

A cláusula defined by não é indispensável em todos os casos. Neste caso foi, porque não especificá-la, GeneXus determinaria como tabela base do For each principal CUSTOMER, que não é o quequeremos (pois não queremos implementar um join, como foi feito antes, e sim um corte de controle,para ler somente a tabela INVOICE).

Poderíamos ter utilizar outra solução para modificar a tabela base do For each principal: utilizar em vezdo defined by o comando print if detail dentro do corpo do primeiro For each (este comando diz aoGeneXus que tome como tabela base do For each, a mesma que determinar para o aninhado).

Page 44: 07 procedures-curso gxxbr

���

Um controle de corte é fácil de programar e pode ser feito seguindo as considerações anteriores.Na ordem do For each mais extremo, devemos mencionar o “primeiro” atributo de corte, na ordem dosegundo For each devemos mencionar o “segundo” atributo de corte e assim sucessivamente. Não éobrigatório mencionar atributo/s na ordem do For each mais interno (em todos os demais For each éassim).

É utilizado quando desejamos trabalhar com a informação de uma tabela, mas agrupada por algumatributo ou conjunto de atributos.

Os controles de cortes podem ser simples, duplos, triplos, etc.

A seguir veremos um exemplo de um controle de corte duplo.

Page 45: 07 procedures-curso gxxbr

���

Exemplo: Controle de corte duplo

Vamos supor que queremos como antes listar os clientes e suas faturas, mas queremos agrupar asfaturas de cada cliente por data. Isto é, queremos mostrar, para cada cliente, para cada data, asfaturas existentes.

Exemplo:

Customer: 1 João Silveira

Date: 12/05/05Invoice Id Invoice Amount

1 15

Date: 01/01/06Invoice Id Invoice Amount

9 353 30

Customer: 3 Maria Silva

Date: 06/06/05Invoice Id Invoice Amount

2 20

Date: 12/08/05Invoice Id Invoice Amount

4 408 15

Date: 02/02/06Invoice Id Invoice Amount

7 20

Como agora queremos agrupar por cliente, e dentro desse grupo por data de fatura, necessitamos trêsFor eachs aninhados:

For each order CustomerIddefined by InvoiceDate

print customerFor each order InvoiceDate

print dateFor each

print invoiceEndfor

EndforEndfor

Como exercício, vamos seguir todos os passos que realiza GeneXus para inferir o comportamento doprocedimento.

1. Determinação da tabela base de cada For each

Como sempre, para determinar as tabelas base de For eachs aninhados, se começa de fora paradentro, determinando de cada For each, sem levar em consideração os atributos dos For eachsinternos ao que se está considerando.

Page 46: 07 procedures-curso gxxbr

���

2. Determinação da navegação

Depois de determinadas as tabelas base, GeneXus determina a navegação. Como neste caso são três For eachssobre a mesma tabela base, se trata de um controle de corte duplo.

Podemos pensar que quando falamos de controle de corte, seja simples, duplo, triplo, quádruplo, etc, temos somenteum ponteiro utilizado para avançar nos registros da tabela base.

Lembremos que a cláusula order é fundamental para estabelecer o critério de corte em cada par de For eachs.

Como em nosso caso queremos agrupar por CustomerId e depois, para todas as faturas com esse cliente, agruparpor InvoiceDate, então teremos que ordenar o primeiro For each por CustomerId e ou imediatamente aninhado porInvoiceDate.

No exemplo estamos dizendo que:

Enquanto não encontrar o final da tabelaImprimir os dados do cliente da fatura atualEnquanto não mude o cliente

Imprimir a data da fatura atualEnquanto não mude a data

Imprimir os dados da fatura atual (Id e Amount)Avançar o ponteiro ao seguinte registro

��������������������������������� ���������� �!" �#������������������ ���������� �� ������������� �������

$�����$�����

$�����

��������� ������������

%��"�����#��"�� ���! �"���"�&!'���"�(!���" ����#���'�� ������#�� ���"��&�"��" ������&!)��"�����" �������������*���������+��� ���"���� ��#������#�"#�� ���&����"�,��������

��������������������������������� ���������� �!" �#���������������������������� ���������������� ��-����

$�����$�����

$�����

����������������������

%��"�����#��"�� ���! �"���"�&!'���"�(!���" ����#���'�� ������#�� ���"��&�"��" ������&!)��"�����" �������������*���������+��� ���"���� ��#������#�"#�� ���&����"�,��������

��������������� ���������������������������� ������������������������ ���������� �� ������������� ��-����

$�����$�����

$�����

����������������������

.�#�� ��"������"�������"��"�� ���! �"���"�&!'���"�(!���" ����#���'�� �*/)��#�� ���&���" �������(!���"���� �#,��" 0�������1

Page 47: 07 procedures-curso gxxbr

���

Recomendamos programar em GeneXus este procedimento e observar cautelosamente a listagemde navegação.

Verá que GeneXus escolhe uma única ordem, quando não tem um índice criado: o composto pelaconcatenação das ordens de cada For each com cláusula order. Este resultado é claro se pensarmosque um único ponteiro vai se deslocando pela tabela base.

Uma vez determinado a Order do Controle de Corte se otimiza, buscando o melhor índice levandoem consideração as condições explícitas ou implícitas do nível.

Resumo: Determinação geral das tabelas Base

Acontece de forma ordenada, determinando cada vez a tabela base de um nívelaninhado, vendo de fora para dentro: primeiro determina-se a tabela base do Foreach mais externo, depois o que está aninhado a este e assim sucessivamente.

Determinação da Tabela Base do For Each ExternoDetermina a partir dos atributos que aparecem dentro desse For each: cláusulas order, where,defined by e corpo do For each, exceto os atributos que estejam dentro do For each aninhado. Nãoparticipam os atributos que estão dentro do When none, no caso do For each principal ter estacláusula. Como no caso de um For each simples, que se encontra a mínima tabela estendida quecontenha ditos atributos.

Determinação da Tabela Base do For Each AninhadoPodemos chegar a pensar por analogia que deveríamos extrair os atributos do For each aninhado, efazer o mesmo que antes, ou seja, encontrar a mínima tabela estendida que contenha essesatributos, como se fosse um For each independente. Mas não são For eachs independentes!

Para o For each aninhado, o GeneXus verifica se os atributos utilizados dentro do corpo do mesmoestão incluídos ou não dentro da tabela estendida previamente determinada. Em caso afirmativo, oGeneXus determina que a tabela base do For each aninhado será a mesma que a do For eachprincipal ( e será um caso de controle de corte)

Caso contrário, se determina da seguinte maneira: busca a mínima tabela estendida que contenha atodos os atributos do For each aninhado, tratando de encontrar aquela que tenha alguma relaçãocom a tabela base do For each principal.Se não encontra uma tabela estendida que contenha a todos os atributos do For each aninhado eque além desta relacionada, fica com a tabela estendida mínima que contenha os atributos ainda quenão tenha relação.

Page 48: 07 procedures-curso gxxbr

���

Os comandos introduzidos são similares aos existentes nas linguagens de Programação imperativaconhecidas, por isso não incluímos a documentação deste tema. Pode ser encontrada no curso nãopresencial ou no Help do GeneXus. Os dois últimos, incorporam alguns elementos importantes sobreadministrar arrays e de coleções1 em GeneXus. Pelo qual mostraremos alguns exemplos:

For to step:• inicio, fin são expressões num�ricas• salto é uma constante num�rica• var é alguma variável num�rica• bloque é uma sucessão de comandos v�lidos da linguagem

Permite interagir certa quantidade de vezes: desde o valor início que toma a variável &var quando seingressa ao loop, até o valor fim que toma a mesma quantidade de interações. De interação eminteração a variável &var vai incrementando automaticamente numa quantidade igual a passo. Ovalor por default de salto é 1, senão especificarmos a cláusula step o incremento da variável seráde um em um. O valor de salto pode ser negativo e nesse caso irá decrementando a variável deinteração em interação.

ExemploFor &i = 1 to 5

&ok = PInvoicing.udp( &month )Endfor

_____________________________________________________________________________1 As coleções representam listas de tamanho variável. Serão vistas quando estudarmos o tipo dedados estruturado (SDT).

Page 49: 07 procedures-curso gxxbr

��

For in Expression:• Expression é qualquer expressão cujo valor seja uma coleção, vetor ou matriz.• var é uma variável que deve ter o mesmo tipo de dados que os elementos de Expression.

Esta estrutura de programação permite percorrer com menos c�digo uma coleção ou uma variável vetor de uma oumais dimensões. Se armazena na variável &var os valores de cada elemento da coleção, vetor ou matriz.

Para o caso de vetores de uma dimensão:

for &var in &varArray()… // code

Endfor

o c�digo se expande (é equivalente) a:&x = 1

do while &x <= rows(&array())&var = &Array(&x)bloque&x += 1

enddo

No caso de duas dimensões:

for &var in &varMatrix()… // code

Endfor

o comando se expande (é equivalente) a:&x = 1 do while &x <= rows( &array() )

&e = 1do while &e <= cols( &array() )

&var = &array( &x, &e )bloque&e += 1

enddo&x += 1

enddo

Também pode ser uma variável coleção de qualquer tipo, incluindo uma variável com a propriedade Collection em'False'mas de um tipo de dados 'SDT collection'.

for &var in &collection...endfor

A expressão também pode não ser uma variável, por exemplo no caso do resultado de um DataProvider ou de umProcedure:

for &var in DataProvider(parms)...Endfor

for &var in Procedure(parms)...endfor

Considerações:

• Não é possível modificar os valores da coleção, vetor ou matriz na percorrida. Isto significa que alterações no valorde &var no alcance da estrutura, não afetam ao correspondente valor da &collection o do &array(&x), ou de&array(&x, &e)).

• Não é possível obter a posição da coleção/array/matriz durante a percorrida, para isto é necessário definir umavariável que at�e como contador.

•Estas estruturas podem aninhar para percorrer vários arrays, matrizes ou coleções. Isto inclui o caso de que sechame uma Subrotina que tamb�m possui um For In Expression.

•Igual que em um For Each ou um Do While, é possível incluir comando que �corte� a percorrida, como Exit ou Return.

Page 50: 07 procedures-curso gxxbr

��

Aqui veremos alguns comandos de impressão, que permitem desenhar a saída do procedimento.

PrintOnde nomePrintBlock é o identificador de um Printblock do Layout. Não existindo no Layout um Printblockcom esse nome, ao tentar salvar o objeto mostra-se uma mensagem de error informando sobre estasituação.

Desta forma implementa-se a impressão na saída dos Printblocks do Layout.

Quando o Printblock que se quer imprimir não contêm atributos, então este comando pode ser utilizado emqualquer lugar do Source.

Os atributos indicam acesso a base de dados e este acesso não pode ser realizado em qualquer lugar,somente dentro do comando específico para ele, isto é, o comando For each.

Portanto, não é correto escrever o comando print fora de um “For each” se o Printblock que desejamosimprimir contêm atributos.

A �nica exceção desta regra se produz quando os atributos do Printblock est�� incluídos entre osparâmetros recebidos pelo procedimento, pois neste caso não é necessário acessar a base de dados pararecuperar seus valores, visto que já vem instanciados.

HeaderAqu� se define o que se quer imprimir como cabeçalho de cada p�gina da listagem.Este cabeçalho é opcional. Se não for especificada, então as p�ginas da listagem não terão cabeçalho.

Exemplo: No procedimento que quer�amos imprimir uma listagem com o c�digo, nome e pa�s de cada umdos clientes de nosso sistema, se queremos que em cada p�gina da listagem apareça o cabeçalho:�CUSTOMERS REPORT�, então é suficiente escrever no Source:

HeaderPrint title

End

Onde �title� é o nome de um Printblock do Layout que contem este texto.

Page 51: 07 procedures-curso gxxbr

���

Também poder�amos ter escrito diretamente: Print title no início do Source, mas neste caso, se alistagem tem várias p�ginas, somente sairá impresso este texto na primeira. No outro caso, sairá emcada uma das p�ginas, como cabeçalho.

FooterDefine as linhas no rodapé da página a ser impressas ao final de cada página do procedimento.

Os comandos do bloque de código são executados quando se chega ao final de uma página.

Exemplo:Footer

print endOfPageTextend

onde endOfPageText é o nome de um Printblock do Layout

Page 52: 07 procedures-curso gxxbr

���

Desenho da saída

Existem alguns comandos para desenhar a saída do procedimento. Apresentamos aqui algunsefeitos da documentação.

MT nlines: nlines é o número de linha em que se quer começar a imprimir a listagem. Caso não sejaespecificado um valor se assume o valor por default que é 0.

MB nlines: nlines é o número de linhas que se deseja deixar como margem inferior.Caso não seja especificado um valor se assume o valor por default que é 6.

PL nlines: Seta o tamanho de página. O número de linhas que será impresso é o númeroespecificado menos a margem de baixo (valor por default é 6). Ex: PL 66Seta o tamanho da página a 66 linhas, ainda que somente 60 linhas sejam impressas no form, comuma margem inferior de 6 linhas.

CP nlines: Se quiser na página atual um número de linhas maior ou igual ao número especificado,continua imprimindo na mesma página. Do contrario, passa a imprimir na próxima página (força umsalto de página).

Lineno nlines: Define o número de linha onde vai ser impressa a seguinte linha. Se o número delinha atual é maior ao número especificado, então, a linha será impressa na próxima página. O delinhas começa na linha 0.

Eject: Força a um salto de página.

Noskip: Tem que estar imediatamente depois de um Printblock. Se o comando se encontra entreduas linhas, este comando as imprimirá na mesma linha.

Page 53: 07 procedures-curso gxxbr

���

Em Web as listagens somente podem ser PDF e devem ser configuradas as propriedades e regrasanteriores para que funcionem.

Definição de um objeto como main

Ao definir que um objeto é main (neste caso um procedimento, mas poderia ser uma transação,web panel, etc.), GeneXus gera um programa executável com a lógica do objeto mesmo e a detodos os objetos chamados direta ou indiretamente por ele.

O programa executável gerado pode compilar e executar de forma independente, isto é, aoselecionar Build / Run se verá como programa independente do Developer Menu e poderácompilar-se e executar-se.

A definição de um objeto como main se realiza editando as propriedades do objeto, e configurandoa propriedade Main program do mesmo com valor True.

Page 54: 07 procedures-curso gxxbr

���

Nesta seção se permite estabelecer condições que devem cumprir os dados para ser recuperados.

Uma “condição” é equivalente a cláusula “where” do comando for each (tem a mesma sintaxe) comuma diferença: enquanto a cláusula “where” está ligada à um For each específico - aquele ao quepertence -, as “condições” estão ligadas à todos os For each do Source que tenha sentido aplicá-las.

E para que For eachs tem sentido aplicá-las?As Condições geralmente envolvem atributos. Se na tabela estendida de um For each encontra-sealgum dos atributos que interferem numa “condição”, então a mesma pode ser aplicada à este Foreach para filtrar os dados ficando unicamente com aqueles que satisfaçam tal condição.

Na listagem de navegação do procedimento indicam-se os For eachs que aplicam-se a cadacondição das especificadas na seção “Conditions”.

Se no Source do procedimento “PrintCustomers” temos:

For eachPrint customer

Endfor

Então ao especificar as condições que se mostram no slide, estaremos filtrando os clientes, deacordo com as condições (é equivalente ter as condições como “where”).

Page 55: 07 procedures-curso gxxbr

���

onde:• “customer” é um Printblock que contem os atributos CustomerId, CustomerName, CountryName• “invoice” é um Printblock que contem os atributos InvoiceId, CustomerId, CustomerName,InvoiceDate, InvoiceAmount• “product” é um Printblock que contem os atributos ProductId, ProductDescription, ProductStock

Se o procedimento anterior tem definido as condições mostradas acima, o procedimento seráequivalente a um que não tiver “condições” e com o Source que se mostra a direita.

Observemos que neste caso as condições se traduzem em cláusulas where mas que se aplicamsomente aos For eachs para os que tem sentido aplicá-las. Na tabela estendida do último For eachnão se trabalha com nome de cliente, nem com identificador de fatura. Não tem sentido aplicar ascondições neste For each já que não existe nenhuma relação.No primeiro, somente tem sentido aplicar se utilizar CustomerName e não a outra.

ObservaçãoOs atributos envolvidos nas “condições” não participam na determinação das tabelas base dos Foreachs do Source (a diferença dos filtros que se especificam mediante cláusulas where).

Isto é, as tabelas base dos For eachs que apareçam no Source se determinam sem olhar as“condições”. Uma vez determinadas, nesse momento as condições são examinadas para determinara quais For eachs se aplicam e a quais não.

O mesmo ocorre com os atributos recebido como parâmetro. Aplicam como filtro global por igualdadepara os For eachs que tenha sentido, mas não participam na determinação das tabelas base.

Page 56: 07 procedures-curso gxxbr

���

Resumimos aqui as distintas formas de filtrar em um procedimento a informação da base de dados a serrecuperada:

a. cláusulas whereb. condiçõesc. parm( att, ..., att )

Estudemos as diferenças e similaridades entre elas.

1. As cláusulas where aplicam exclusivamente ao For each em que se encontram, enquanto que osfiltros especificados como condições ou os que ficam determinados pelos atributos na regra parm sãoglobais, isto é, aplicam a todos os For eachs do Source em que faça sentido aplicá-las.

2. Os filtros que ficam determinados ao receber atributos na regra parm são filtros por igualdade, isto é,para os For eachs que tenha sentido aplicá-los, se instanciarão unicamente os registros que tenham omesmo valor que o recebido por parâmetro. Por outro lado, os filtros especificados nas cláusulas wherede um For each ou nas condições podem ser expressões booleanas quaisquer, incluso compostas.

3. Enquanto que os atributos que aparecem nas cláusulas where participam na determinação da tabelabase do For each onde se encontram, os que aparecem nas condições ou na regra parm não o fazem.São aplicados ASSIM que determinadas as tabelas base dos For eachs do Source.