SlideShare une entreprise Scribd logo
1  sur  56
Télécharger pour lire hors ligne
Procedimentos:
Definem processos não interativos de consulta e atualização da base de dados. Os procedimentos
podem gerar um arquivo formato PDF, mediante o qual é possível listar informação na tela ou
impressora. 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 de
dados, mas algo um pouco mais complexo, o business component, por meio do qual serão realizados
atualizações a base de dados em qualquer objeto GeneXus. Portanto, utilizando variáveis de tipo de
dados business component, poderão ser realizadas atualizações incluso nos objetos que por
natureza não oferecem esta possibilidade, como as web panels.
Definição procedural
A diferença das regras das transações onde as especificações se realizam de forma declarativa e
GeneXus determina no momento de gerar o programa a seqüência de execução, nos procedimentos
as 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 de
controle, de impressão, de acesso a base de dados, etc.
Definição sobre a base de conhecimento
A grande potencia da linguagem dos procedimentos está que as definições são realizadas sobre a
base de conhecimento e não diretamente sobre o modelo f sico (tabelas, ndices, etc.). Isto nos permite
utilizar autom ticamente todo o conhecimento já incorporado ou gerado por GeneXus a partir das
especificações realizadas.
Por exemplo, se desejamos mostrar o resultado de uma f rmula é suficiente nomear o atributo f rmula
no lugar adequado e GeneXus dispara o c lculo mostrando o resultado, sem necessidade do analista
oferecer nenhuma outra informação. A informação de como se calcula um atributo f rmula est contida
na base de conhecimento.
Também podemos utilizar o conceito de tabela estendida, já que GeneXus conhece as relações entre
as tabelas da base de dados, o analista não precisa explicitar estas relações na hora de recuperar
dados.
Independência da base de dados: definição a nível de atributos
A definição dos procedimentos se faz a nível de atributos: não é necessário indicar expl citamente
quais tabelas ser ndices. Somente mencionando os atributos que
deseja acessar é suficiente para que o GeneXus determine esta informação. Isto é possível porque
GeneXus 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 nas
tabelas ser gerenciado automaticamente pelo GeneXus e desta forma, para atualizar os programas
alcança em grande parte das vezes, como regerar os objetos sem ter que modificar nada do
programado neles.
Para cada procedimento se pode definir:
• Source: Aqu o c digo correspondente a l gica do procedimento. Também podem definir-se ao final
do 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 o
uso 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.
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 uma
delas a representaremos com um Printblock.
Os primeiros dois Printblocks ilustram no GeneXus tal qual as primeiras duas reas pois contem
unicamente textos, linhas, retângulos. Também poderíamos ter colocado estas duas reas
convertendo-as em uma e utilizando portanto um nico Printblock.
O terceiro Printblock ser o correspondente da rea de dados variáveis da figura anterior, que
representa 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 do
pa s ao que pertence. Esta informação é a representada pelos atributos CustomerId, CustomerName
e CountryName da base de conhecimento da aplicação, o terceiro Printblock conter os três controles
atributo CustomerId, CustomerName e CountryName.
Transformando as reas em Printblocks, o Layout do procedimento ficará como o da figura na p gina
seguinte.
O Layout de um procedimento será uma sucessão de Printblocks que não tem por que seguir a
ordem em que deseja que apareçam na saída.
No exemplo anterior, o mesmo procedimento teria sido impresso se houvesse especificado os
Printblocks na ordem inversa (ou em qualquer ordem).
Aqui simplesmente são declarados. A ordem que são executados fica determinado na seção Source
que é a que contem a lógica do procedimento. A partir dali serão chamados mediante um comando
especí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 do
Source.
No exemplo, para listar todos os clientes, o Printblock de nome “customer” deve ser chamado dentro
de uma estrutura repetitiva no Source. Esta estrutura repetitiva é o comando For each que
estudaremos depois.
O Printblock é um tipo de controle v lido somente nos procedimentos, que é inserido e eliminado do
Layout pelo analista, e que contem outros controles -atributos, textos, retângulos, linhas, etc.-, sendo
estes 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 se
utiliza para inserir os controles no Layout. De fato esta toolbox está disponível para todos os objetos
GeneXus 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 Insert
Printblock.
Como todo controle, o Printblock possui propriedades que podem ser configuradas pelo usuário. Em
particular, tem a propriedade “Name”, muito importante visto que é o identificador do Printblock. Com
este 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 ou
View/Properties.
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 de
alguns comandos que veremos.
O estilo de programação é procedural – imperativo – o Source será uma sucessão de comandos
onde a ordem é fundamental: a ordem em que estejam especificados corresponderá, exceto
exceçõ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 dentro
de um loop (exit) ou abandonar o programa (return), assim como também comandos específicos
desta linguagem: para imprimir um Printblock do Layout (print), para acessar a base de dados (For
each), 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, podem
definir-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 os
comandos de controle, que são comuns a todos as linguagens de programação imperativa, os
comandos de atribuição e os de impressão.
A definição do acesso a base de dados para recuperar a informação se realiza com um único
comando: o comando For each1.
Usando o For each se define a informação que vai acessar. A forma de o fazer é baseada em nomear
os atributos a utilizar.
Assim, com este comando se definem quais atributos são necessários em qual ordem vai ser
recuperada, e GeneXus se encarrega de encontrar como fazer. Não se especifica de quais tabelas se
devem 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 de
erro 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 a
especificação do procedimento é de mais alto nível possível, de tal forma que ante mudanças na
estrutura 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 ou
navegada. 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 se
consegue consultar a base de dados.
Intuitivamente com este comando queremos listar identificador, nome e país de cada um dos clientes
da base de dados. Ou seja, queremos percorrer à tabela CUSTOMER, e para cada cliente seja
recuperado da tabela COUNTRY o nome do país ao qual pertence, imprimindo esta informação, junto
com o identificador e nome do cliente. (Observar que a tabela COUNTRY pertence à estendida de
CUSTOMER)
Como o GeneXus infere isto, só o que fizemos foi For each do exemplo informar os atributos que nos
interessava mostrar?
Dentro de todo For each navega-se - percorre ou itera - a tabela base, mas podemos acessar as
tabelas que constituem sua tabela estendida para recuperar a informação, por pertencer a
estendida está relacionada com cada registro da tabela base com que esteja trabalhando em cada
interação (o conceito de tabela estendida é muito importante neste comando e sugerimos repassar
sua 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 tabela
COUNTRY (que está na estendida de CUSTOMER). Dizemos então que se percorre CUSTOMER e
se 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 ao
GeneXus esta informação. Não é necessário, já que o GeneXus conhece as relações entre as
tabelas, e na base os atributos mencionados dentro do For each e pode encontrar sem necessidade
de mais informações uma tabela estendida que os contenha.
A tabela base dessa estendida é escolhida como tabela base do For each.
A tabela base correspondente a essa tabela estendida é chamada de tabela base do For each
e será percorrida seqüencialmente, executando para cada registro o que for indicado nos
comandos internos do For each.
Para o exemplo apresentado onde queremos uma lista dos clientes: seu identificar, nome e nome de
país, observamos os atributos utilizados dentro do For each, e percebemos que eles são os contidos
no 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 tabelas
nas quais aparecem os atributos do For each (Tools/Diagrams).
Aqui podemos ver porque do requerimento da tabela estendida seja a mínima (entendendo por
mínima aquela que envolve um número menor de tabelas). A tabela estendida de INVOICE também
contêm todos os atributos do For each, mas não é mínima, pois a de CUSTOMER também os
contêm.
Portanto, se vamos percorrer seqüencialmente à tabela CUSTOMER, e para cada registro dessa
tabela, 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 atributo
CountryName, para poder imprimi-lo, junto com o código e nome do cliente.
Listagem de navegação
GeneXus oferece para todos os objetos uma lista conhecida como listagem de navegação, que é o
resultado da especificação do objeto. Esta listagem é muito útil para os relatórios, já que indica quais
são as tabelas que são acessadas em cada For each do Source, se existe um índice para recuperar
os dados da tabela base, e em caso de que assim seja qual é esse índice (seu nome), se aplicam
filtros 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á percorrendo
a 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ão
impressos), se existe um índice que satisfaça essa ordem, qual é seu nome, e aparecem mais duas
informaçõ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 chave
primária, e endentadas todas as tabelas da estendida que devam ser acessadas para recuperar a
informação associada ao registro da tabela base que está sendo trabalhada em cada interação do
For each. Neste caso se mostra somente a tabela COUNTRY.
No comando For each do Exemplo não aparece explicitamente nenhuma informação referente a
ordem desejada da impressão da informação do relatório. Neste caso GeneXus escolhe a ordem da
chave 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 tabela
CUSTOMER.
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 dentro
de uma faixa inserida pelo usuário, então devemos agregar ao For each que havíamos visto uma cláusula
where, para especificar os filtros desejados sobre os dados:
For each
where (CustomerName >= &Start) and (CustomerName <= &End)
print customer
Endfor
onde as variáveis &Start e &End devem ser definidas no procedimento com o mesmo tipo de dados que
CustomerName, 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 tabela
base, 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 ter
programando 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ção
booleana 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 da
seguinte forma: os filtros estabelecidos pelo where são aplicados somente quando o when é satisfeito. Isto é lido
da 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 os
clientes (como se não existissem os comandos where).
Cada condição booleana de um “where” pode estar composta de várias expressões booleanas concatenadas
com 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.
Listagem de navegação
Aparece um novo elemento nesta listagem que não existia, quando não tínhamos cláusulas where: os
constraints (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 ICUSTOMER
correspondente
• 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 estiver
vazio) e somente caso se cumpra, executar para esse cliente os comandos que aparecem dentro do
For 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)
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 serem
recuperados utilizando o atributo CountryName, que é da tabela COUNTRY, pertencente à tabela
estendida de CUSTOMER.
Neste exemplo nada foi feito em relação à ordem, os dados aparecerão ordenados pela chave
primária da tabela base, ou seja, pelo identificador de cliente, CustomerId.
.
Se queremos realizar uma lista de todos os clientes, ordenado por nome do cliente ao invés do
có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 GeneXus
indicará na listagem de navegação mediante uma advertência (“warning”) que não existe um índice
para satisfazer a ordem, o que pode ocasionar problemas de performance, dependendo da
plataforma 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 traduz
numa 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 ser
condicional,como o exemplo dois.
Caso a condição when não for cumprida, essa ordem não será utilizada e não existir ordem
incondicional (sem a cláusula when) como no exemplo, a ordem será indefinida, isto é, a ordem
poderá 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 arquiteturas
cliente/servidor e uma sem condição (a última da lista). O primeiro comando order cuja condição do
when 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 da
chave 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 ordem
em particular e delega esta tarefa ao DBMS.
A cláusula order none pode ter condição (when).
Listagem de navegação
Quando não existe um índice que satisfaça o ordem de um For each, como é o caso do Exemplo, o
analista 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 maior
processamento 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 de
usuário), portanto deve-se estudar, caso por caso, a solução particular levando em consideração a
plataforma 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 posteriormente
decide-se fazê-lo, somente é preciso que o relatório seja gerado novamente (sem modificar nada do
que 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 For
each (neste caso, o comando print)
Se queremos filtrar os clientes por determinada faixa de nomes, o primeiro exemplo, como não foi
especificada 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, e
para cada registro da mesma deve-se analisar se o registro cumpre ou não as condições (restrições
ou “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 nos
filtros estabelecemos que queremos somente aqueles clientes cujo nome, CustomerName, esteja na
faixa determinada, já não sendo necessário recorrer toda a tabela base para obter os dados que
cumprem 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 que
seja criado um índice temporário em execução para resolver a consulta se o DBMS não pode fazer
de 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
A listagem de navegação nos informa que a consulta está otimizada já que percorre somente os
registros 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 ou
condições explícitas por igualdade, se busca se existe um índice que contenha os atributos
das condições mais os do Order. A condição explícita prevalece sobre a implícita para a
determinaçã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 que
dito í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 determinado
pelos atributos do índice.
•Se não existe um índice que corresponda com as condições, ou seja que não se pode
otimizar a percorrida segundo as condições do nível, então se ordena pelos atributos da
Primary Key.
Por exemplo, se temos as transações:
COUNTRY CITY
{ {
CountryId* CountryId*
} CityId*
}
O For each:
For Each order CityId
Where CountryId = 1
...
Endfor
Percorre a tabela CITY, ordenando por: CountryId, CityId e utilizando o índice ICITY (índice por chave
primária que contem ambos atributos).
Ainda é o próprio DBMS que resolve o plano de acesso mais apropriado, a informação antes
mencionada influirá em sua determinação.
Pode ocorrer de que um For each tenha mais de uma tabela base cuja estendida contenha os atributos do For
each, sendo mínima. Frente esta ambigüidade, GeneXus escolhe a “primeira” destas tabelas estendidas
mínimas.
Para resolver este tipo de ambigüidade surge a cláusula defined by, que permite usar atributos da tabela base
desejada, que não serão utilizados para devolver a consulta ordenada por esses atributos, nem para filtrar
informaçã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 atributo
mais dentro do For each. Este é o caso do exemplo apresentado, não que não queremos listar todos os clientes
da tabela CUSTOMER, pelo contrário, queremos listar todos os clientes das faturas. Se não utilizar nenhum
atributo 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 tempo
de 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 atributo
secundário. Se quisermos uma listagem dos clientes e seu país, seriam equivalentes:
For each For each
Defined by CountryName
print customer print customer
Endfor 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 For
each continuará sendo válido e fazendo o que queremos, o segundo deixará de funcionar, ja que no Defined By
não tem nenhum atributo da tabela base.
Podem aparecer vários atributos, no caso de um único atributo não determinar a tabela base, onde
ao 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 forma
eliminamos por completo toda possível ambigüidade.
Isto não é obrigatório, podemos usar no Defined by para atributos primários quando notarmos que
nã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 fica
determinada exclusivamente a partir dos atributos mencionados no defined by.
A realidade é que os atributos do defined by determinam uma ou mais tabelas base candidatas a
serem a tabela base do For each, mas tendo selecionado a tabela base candidata, sua estendida
contê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 For
each devem estar contidos em uma mesma tabela estendida).
O Printblock menssage (poderá ter um texto advertindo ao usuário que não existam clientes que
cumpram os filtros) executa somente quando não entrar no For each, isto é, quando não tem nenhum
registro 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 mais
adiante.
A cláusula when none deve ser a última dentro do For each. As ações a serem realizadas quando
não existe nenhum registro que cumpra as condições, ficam determinadas pelo bloque de código que
tem 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 executados
somente no caso em que a tabela base do For each esteja vazia, porque somente nesse caso não
haverá 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 levados
em 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 com
respeito ao For each que contêm o When none, já que são considerados dos For eachs paralelos.
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 de
conhecimento escrito simples, ou entre parênteses. Quando um atributo do order aparece entre
parê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 última
listada. Respondendo ao fato de que somente uma dessas cláusulas order tomará efeito, se vão
avaliando suas condições (as do when) até a primeira que de True, e com essa fica. Se nenhuma
der true e existe uma cláusula incondicional (isto é, sem when), pega essa ordem. Se não existe tal
cláusula, ou ordem será indefinido, querendo isto significa que dependerá da plataforma, e incluso
poderá variar entre execuções sucessivas. A justificatova para escrever cláusulas order
condicionais, deriva se quisermos aplicar cláusulas where condicionais. Isto é, por motivos de
otimização das consultas.
Por exemplo, se queremos filtrar por CustomerName > &Name when not &Name.IsEmpty(), então
para otimizar a consulta deveríamos ordenar por CustomerName, mas se não aplicar o filtro, visto
que &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.
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 de
dados. 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 Where
como 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 sua
determinaçã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ão
determinam. Devem examinar-se também outras partes do For each.
Using DataSelectorName
Permite definir filtros de acordo ao critério definido no DataSelector1 definido em DataSelectorName.
Where Condition
Condição booleana que deverão cumprir os dados para ser processados dentro do For each, podendo ser uma condição
composta, 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 com
uma condição:
where cond1
where 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 nos
comandos 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 se
avalia 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 se
está 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 do
DBMS) se transformará em um filtro "comum" substituindo o WHEN por um OR. Além disso, se gerar a mensagem de código
spc0053 – ‘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 de
valores dos atributos referenciados. Não veremos esta cláusula. O leitor interessado pode recorrer as distintas fontes de
documentação para estudá-la (Help, Wiki, Release Notes, etc.)
Defined by
defined_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 For
each.
A cláusula defined by aparece para solucionar alguns problemas de ambigüidade na determinação da tabela base (quando
existem várias tabelas estendidas mínimas que contenham os atributos do For each) ou quando se deseja que a tabela base seja
outra, diferente da que seria determinada pelos atributos que aparecem no resto do For each (este caso tem sentido quando se
estude “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 atributos
determinam tabela como a candidata a tabela base, mas se depois os outros atributos do For each não estão contido na
estendida 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 o
chamaremos 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.
Os comandos especificados serão executados seqüencialmente para os dados da tabela estendida que cumpram
as Condições de filtro, considerando os dados na ordem especificado.
Blocking
Este tema será abordado mais adiante do curso, mas a idéia geral é que a especificação desta clásula permite
realizar atualizações e eliminações em blocos, reduzindo assim o número de acesso a base de dados.
When Duplicate
Esta 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 a
unicidade 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 none
Em caso de que não existam dados que cumpram as Condições de filtro não será executado os comandos do
code1 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 dos
dois, 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).
Os code snippets são moldes de c digo que GeneXus tem predefinido, que nos ajudam a
escrever o c digo fonte. Quando estamos trabalhando no Source de um procedimento, a
Toolbox 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 seja
mais r pida todav a. Por exemplo, digitando simplesmente fe se escreve autom icamente o
seguinte 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)
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 For
eachs 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 aninhados
porque 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 registro
da 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 tabelas
INVOICE e BILL (recibo) respectivamente.
Temos definido dois For eachs paralelos. O primeiro percorre todas as faturas e o segundo todos os
recibos.
O For each é uma estrutura repetitiva, que permite recuperar muitos registros de uma tabela. Quando
pensamos em For eachs aninhados, é evidente que o que buscamos recuperar é, para cada registro do
principal,muitos registros do aninhado.
O que o GeneXus detecta que se quer fazer com este tipo de estruturas, de forma de inferir o
comportamento 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 um
atributo ou conjunto de atributos e para cada grupo, recuperar alguns registros: os correspondentes ao
grupo.
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 eachs
aninhados, 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 imprimiremos
detalhe de cada uma, devemos navegar por duas tabelas: INVOICE (que armazena os cabeçalhos) e
INVOICEDETAIL (que armazena as linhas), e o faremos de uma forma bem simples, sem colocar o
nome 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 seus
dados pessoais, os dados de todas suas faturas. Este comportamento se dá com um par de For eachs
aninhados, onde o primeiro navega pela tabela CUSTOMER e o segundo navega pela tabela INVOICE,
recuperando somente as faturas desse cliente, como veremos em seguida.
Se queremos realizar uma lista de todas as faturas do sistema, onde para cada uma se mostre tanto
a informação do cabeçalho como das linhas.
No Source programado, percorremos à tabela INVOICE, imprimindo os atributos que nos interessam
do cabeçalho e para cada registro dessa tabela, percorremos a tabela INVOICEDETAIL, para
imprimir os atributos que nos interessam de suas linhas.
Podemos perceber o quão simples é esse processo, simplesmente utilizando os atributos que
queremos usar, ficando o GeneXus encarregado do resto.
Observemos que nem sequer tivemos que especificar a condição de filtro sobre os registros de
INVOICEDETAIL a recuperar. O GeneXus se dá conta da relação existente entre as tabelas, e aplica
automaticamente 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ão
precisa que especificá-la).
Como para um For each simples, o GeneXus deve determinar para cada For each (principal e
aninhado) 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. Aqui
ficaremos com idéia intuitiva de que o faz de forma similar como o fazia no caso de um For each
simples.
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: infere
também na aplicação da condição sobre os dados de INVOICEDETAIL que indicamos acima.
Quando temos dois For eachs aninhados,GeneXus deve determinar a tabela base de cada um, e
essas 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 do
mesmo. Entre esses comandos, encontra-se o For each interno, que será executado, como qualquer
outro 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 each
principal, mas as determinações não são por completo independentes, como se pode pensar
equivocadamente.
A partir da determinação das tabelas base de cada For each e das relações que encontre o
GeneXus entre as tabelas envolvidas, surgem três possíveis casos de For eachs aninhados, que
correspondem aos casos enunciados anteriormente: join, Produto cartesiano e corte de controle,
respectivamente.
Estudaremos cada um desses casos com exemplos.
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 encontra
a mínima tabela estendida que os contenha e define assim a tabela base através da qual chega a
todas as outras.
• Para determinar da tabela base do for each aninhado, GeneXus fixa os atributos utilizados
dentro do corpo do mesmo, onde estão incluídos ou dentro da tabela estendida previamente
determinada (a do For each principal). Em caso afirmativo, GeneXus determina que a tabela base do
For 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 do
For each aninhado e que tenha alguma relação com a tabela base do For each principal. A tabela
base 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 cumpre
que contenha os atributos, finalmente a escolhe, mas sempre busca a forma de encontrar relações
entre ambas tabelas bases. Somente neste último caso de não se encontrar relações, se procede a
determinar a tabela base como se fosse For eachs independentes.
Estudaremos um esquema resumindo o anterior depois.
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 de
INVOICE (que é a tabela base do principal), então se passa a determinar sua tabela base como se
explicou anteriormente: se busca a tabela estendida mínima que contenha a ProductDescription,
ProductPrice, InvoiceLineQuantity e InvoiceLineAmount, e caso possível esteja reacionada com
INVOICE.
A tabela que cumpre ambos requisitos em INVOICEDETAIL.
Da determinação das tabelas base, surgem os três casos de For eachs aninhados que foram
mencionados e que estudaremos um a um em seguida.
Este tema é de vital importância, já que a maioria das aplicações requerem navegações
complexas sobre as tabelas, onde se requer uma mistura de todos estes casos.
Este é o caso em que o GeneXus determina que as tabelas base de cada For each são distintas e tem
uma 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 N
relacionados 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 a
ficar somente com esses registros relacionados.
O exemplo do procedimento que imprime todas as faturas do sistema, com seus detalhes, cai dentro
desta categoria. Nesse caso tem uma relação 1-N direta entre as tabelas que se percorre: para cada
cabeçalho da fatura, lista-se o mesmo, junto com todas suas linhas da fatura, ou seja, todos os
registros 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 para
cada registro da mesma, percorrer outra tabela, relacionada com a primeira por uma relação N-1. O
GeneXus 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, e
a do segundo, INVOICE. Como encontra atributo em comum entre a tabela estendida do For each
principal e a tabela base do aninhado1, CustomerId, determina que esse atributo atue como
condiçã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ção
direta ou indireta 1-N entre as tabelas base. A relação será direta quando a tabela base do principal
tenha relação 1-N com a tabela base do aninhado, isto é, seja superordinada desta última. A relação
será indireta quando isto não exista uma relação direta entre as tabelas base, mas sim entre a tabela
estendida do primeiro e a tabela base do segundo. Também será indireta quando a tabela estendida do
aninhado inclua a tabela base do principal. Veremos exemplos em seguida.
Vejamos, como o GeneXus faz para determinar as tabelas base. Os atributos utilizados no For each
externo 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 each
principal,não os do aninhado.
Depois, GeneXus deve encontrar a tabela base do For each aninhado. Os atributos que participam
sã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 era
CUSTOMER. Portanto passa a determinar sua tabela base como a de qualquer For each simples: a
tabela estendida INVOICE contem todos os atributos do For each aninhado, e é a mínima tabela
estendida que os contenha. Portanto, INVOICE será escolhida como tabela base do segundo For
each.
Observemos, novamente, que não explicitamos cláusula where no For each aninhado para filtrar as
faturas do cliente do For each principal. Justamente, por tratar-se de tabelas relacionadas por uma
relação 1-N direta, esta condição é aplicada implicitamente pelo GeneXus e pode ser visto na
listagem de navegação acima.
Outro fato interessante que pode ser observado nesta lista: no For each aninhado não foi
especificado a cláusula order, GeneXus não escolheu a ordem da chave primária da tabela base e
sim pelo atributo da relação, CustomerId. Desta maneira, está otimizando automaticamente a
consulta.
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 dito
For each.
Se queremos realizar uma listagem das faturas emitidas pelo país, teremos outro caso de For eachs
aninhados 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 encontrar
somente um país relacionado à mesma.
Este é um caso um pouco mais complexo que o anterior, porque a tabela estendida do For each
principal não tem intersecção com a tabela base do aninhado (est(COUNTRY) ∩ INVOICE = φ), mas
existe 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 as
faturas 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ão
pode otimizar a percorrida.
O leitor pode testar este caso em GeneXus e estudar detalhadamente a listagem de navegação
resultante.
Neste caso o GeneXus não encontra uma relação 1-N direta ou indireta entre as tabelas e portanto
não aplica filtros implícitos aos registros do For each aninhado, ou seja, realiza um produto cartesiano
entre 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 each
aninhado.
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ão
condições implícitas inferidas pelo GeneXus, mas sim especificadas explicitamente pelo
programador.
.
No exemplo que vimos anteriormente, da listagem de clientes e suas faturas, o que acontece se um
cliente não possuir faturas?
Como a tabela base do For each principal é CUSTOMER, o cliente sai impresso antes de saber-se se
tem 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, é porque
está em uma fatura!.
Mas para poder agrupar as faturas por cliente, de tal forma de poder mostrá-las desse modo, devemos
percorrer a tabela INVOICE ordenada por CustomerId. Desta forma processaremos a informação de
um cliente, e depois passaremos ao seguinte, para processar sua informação, e assim
sucessivamente.
Se imaginamos um ponteiro que se vai mostrando sequencialmente pela tabela INVOICE, podemos
escrever 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 o
CustomerName 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 mudou
o cliente).
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 eachs
aninhados que estão no slide acima.
Comparando este código com o que vimos anteriormente para o caso de join, vemos que existem
somente duas diferenças: a cláusula order que aparece neste código, junto com o defined by. Somente
com essas mudanças da lista original, mudamos radicalmente o comportamento, neste caso somente
serã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 funcione
como 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 each
principal,mas sim uma cláusula order.
A cláusula order é indispensável, porque é ela que especifica por qual atributo ou conjunto de
atributos 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 que
queremos (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 vez
do defined by o comando print if detail dentro do corpo do primeiro For each (este comando diz ao
GeneXus que tome como tabela base do For each, a mesma que determinar para o aninhado).
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 do
segundo 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 algum
atributo 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.
Exemplo: Controle de corte duplo
Vamos supor que queremos como antes listar os clientes e suas faturas, mas queremos agrupar as
faturas de cada cliente por data. Isto é, queremos mostrar, para cada cliente, para cada data, as
faturas existentes.
Exemplo:
Customer: 1 João Silveira
Date: 12/05/05
Invoice Id Invoice Amount
1 15
Date: 01/01/06
Invoice Id Invoice Amount
9 35
3 30
Customer: 3 Maria Silva
Date: 06/06/05
Invoice Id Invoice Amount
2 20
Date: 12/08/05
Invoice Id Invoice Amount
4 40
8 15
Date: 02/02/06
Invoice Id Invoice Amount
7 20
…
Como agora queremos agrupar por cliente, e dentro desse grupo por data de fatura, necessitamos três
For eachs aninhados:
For each order CustomerId
defined by InvoiceDate
print customer
For each order InvoiceDate
print date
For each
print invoice
Endfor
Endfor
Endfor
Como exercício, vamos seguir todos os passos que realiza GeneXus para inferir o comportamento do
procedimento.
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 para
dentro, determinando de cada For each, sem levar em consideração os atributos dos For eachs
internos ao que se está considerando.
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 eachs
sobre 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 somente
um 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, agrupar
por InvoiceDate, então teremos que ordenar o primeiro For each por CustomerId e ou imediatamente aninhado por
InvoiceDate.
No exemplo estamos dizendo que:
Enquanto não encontrar o final da tabela
Imprimir os dados do cliente da fatura atual
Enquanto não mude o cliente
Imprimir a data da fatura atual
Enquanto não mude a data
Imprimir os dados da fatura atual (Id e Amount)
Avançar o ponteiro ao seguinte registro
!" #
$
$
$
% " # " ! " "&!' "(! " #
' # " &" " &!) " "
* + " # # "# &
",
!" #
-
$
$
$
% " # " ! " "&!' "(! " #
' # " &" " &!) " "
* + " # # "# &
",
-
$
$
$
. # " " " " ! "
"&!' "(! " # ' *
/) # & " (! "
#, "0 1
Recomendamos programar em GeneXus este procedimento e observar cautelosamente a listagem
de navegação.
Verá que GeneXus escolhe uma única ordem, quando não tem um índice criado: o composto pela
concatenação das ordens de cada For each com cláusula order. Este resultado é claro se pensarmos
que um único ponteiro vai se deslocando pela tabela base.
Uma vez determinado a Order do Controle de Corte se otimiza, buscando o melhor índice levando
em 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ível
aninhado, vendo de fora para dentro: primeiro determina-se a tabela base do For
each mais externo, depois o que está aninhado a este e assim sucessivamente.
Determinação da Tabela Base do For Each Externo
Determina 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ão
participam os atributos que estão dentro do When none, no caso do For each principal ter esta
cláusula. Como no caso de um For each simples, que se encontra a mínima tabela estendida que
contenha ditos atributos.
Determinação da Tabela Base do For Each Aninhado
Podemos chegar a pensar por analogia que deveríamos extrair os atributos do For each aninhado, e
fazer o mesmo que antes, ou seja, encontrar a mínima tabela estendida que contenha esses
atributos, 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 mesmo
estão incluídos ou não dentro da tabela estendida previamente determinada. Em caso afirmativo, o
GeneXus determina que a tabela base do For each aninhado será a mesma que a do For each
principal ( e será um caso de controle de corte)
Caso contrário, se determina da seguinte maneira: busca a mínima tabela estendida que contenha a
todos os atributos do For each aninhado, tratando de encontrar aquela que tenha alguma relação
com a tabela base do For each principal.
Se não encontra uma tabela estendida que contenha a todos os atributos do For each aninhado e
que além desta relacionada, fica com a tabela estendida mínima que contenha os atributos ainda que
não tenha relação.
Os comandos introduzidos são similares aos existentes nas linguagens de Programação imperativa
conhecidas, por isso não incluímos a documentação deste tema. Pode ser encontrada no curso não
presencial ou no Help do GeneXus. Os dois últimos, incorporam alguns elementos importantes sobre
administrar 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 se
ingressa ao loop, até o valor fim que toma a mesma quantidade de interações. De interação em
interação a variável &var vai incrementando automaticamente numa quantidade igual a passo. O
valor 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 de
interação em interação.
Exemplo
For &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 de
dados estruturado (SDT).
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 ou
mais 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 = 1
do 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 um
Procedure:
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 valor
de &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 uma
variá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 se
chame 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.
Aqui veremos alguns comandos de impressão, que permitem desenhar a saída do procedimento.
Print
Onde nomePrintBlock é o identificador de um Printblock do Layout. Não existindo no Layout um Printblock
com esse nome, ao tentar salvar o objeto mostra-se uma mensagem de error informando sobre esta
situaçã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 em
qualquer 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 desejamos
imprimir contêm atributos.
A nica exceção desta regra se produz quando os atributos do Printblock est incluídos entre os
parâmetros recebidos pelo procedimento, pois neste caso não é necessário acessar a base de dados para
recuperar seus valores, visto que já vem instanciados.
Header
Aqu 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 um
dos 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:
Header
Print title
End
Onde title é o nome de um Printblock do Layout que contem este texto.
Também poder amos ter escrito diretamente: Print title no início do Source, mas neste caso, se a
listagem tem várias p ginas, somente sairá impresso este texto na primeira. No outro caso, sairá em
cada uma das p ginas, como cabeçalho.
Footer
Define 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 endOfPageText
end
onde endOfPageText é o nome de um Printblock do Layout
Desenho da saída
Existem alguns comandos para desenhar a saída do procedimento. Apresentamos aqui alguns
efeitos da documentação.
MT nlines: nlines é o número de linha em que se quer começar a imprimir a listagem. Caso não seja
especificado 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úmero
especificado menos a margem de baixo (valor por default é 6). Ex: PL 66
Seta o tamanho da página a 66 linhas, ainda que somente 60 linhas sejam impressas no form, com
uma 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 um
salto de página).
Lineno nlines: Define o número de linha onde vai ser impressa a seguinte linha. Se o número de
linha atual é maior ao número especificado, então, a linha será impressa na próxima página. O de
linhas 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 entre
duas linhas, este comando as imprimirá na mesma linha.
Em Web as listagens somente podem ser PDF e devem ser configuradas as propriedades e regras
anteriores 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 de
todos os objetos chamados direta ou indiretamente por ele.
O programa executável gerado pode compilar e executar de forma independente, isto é, ao
selecionar 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 configurando
a propriedade Main program do mesmo com valor True.
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) com
uma diferença: enquanto a cláusula “where” está ligada à um For each específico - aquele ao que
pertence -, 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-se
algum dos atributos que interferem numa “condição”, então a mesma pode ser aplicada à este For
each 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 cada
condição das especificadas na seção “Conditions”.
Se no Source do procedimento “PrintCustomers” temos:
For each
Print customer
Endfor
Então ao especificar as condições que se mostram no slide, estaremos filtrando os clientes, de
acordo com as condições (é equivalente ter as condições como “where”).
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 aplicam
somente aos For eachs para os que tem sentido aplicá-las. Na tabela estendida do último For each
não se trabalha com nome de cliente, nem com identificador de fatura. Não tem sentido aplicar as
condiçõ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ção
Os atributos envolvidos nas “condições” não participam na determinação das tabelas base dos For
eachs 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 determinar
a 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 igualdade
para os For eachs que tenha sentido, mas não participam na determinação das tabelas base.
Resumimos aqui as distintas formas de filtrar em um procedimento a informação da base de dados a ser
recuperada:
a. cláusulas where
b. condições
c. 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 os
filtros especificados como condições ou os que ficam determinados pelos atributos na regra parm são
globais, 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 o
mesmo valor que o recebido por parâmetro. Por outro lado, os filtros especificados nas cláusulas where
de 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 tabela
base 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.

Contenu connexe

Tendances

Apostila rcmdr 17 01-2013
Apostila rcmdr 17 01-2013Apostila rcmdr 17 01-2013
Apostila rcmdr 17 01-2013Jose llIMA
 
Normalização - Banco de Dados
Normalização - Banco de DadosNormalização - Banco de Dados
Normalização - Banco de DadosRoberto Grande
 
Fundamentos de SQL - Parte 5 de 8
Fundamentos de SQL - Parte 5 de 8Fundamentos de SQL - Parte 5 de 8
Fundamentos de SQL - Parte 5 de 8Emiliano Barbosa
 
Normalização de dados - Primeira forma normal
Normalização de dados - Primeira forma normalNormalização de dados - Primeira forma normal
Normalização de dados - Primeira forma normalvitorleyva
 
Utilizando views, stored procedures e triggers
Utilizando views, stored procedures e triggersUtilizando views, stored procedures e triggers
Utilizando views, stored procedures e triggersDaniel Maia
 
Comandos DDL para o MySQL
Comandos DDL para o MySQLComandos DDL para o MySQL
Comandos DDL para o MySQLArley Rodrigues
 
Normalização básica
Normalização básicaNormalização básica
Normalização básicaNadia Habu
 
Fundamentos de SQL - Parte 6 de 8
Fundamentos de SQL - Parte 6 de 8Fundamentos de SQL - Parte 6 de 8
Fundamentos de SQL - Parte 6 de 8Emiliano Barbosa
 
Sql com sql server básico - Bóson treinamentos
Sql com sql server básico - Bóson treinamentosSql com sql server básico - Bóson treinamentos
Sql com sql server básico - Bóson treinamentosFábio dos Reis
 
TOTVS LINHA RM TREINAMENTO SQL
TOTVS LINHA RM TREINAMENTO SQLTOTVS LINHA RM TREINAMENTO SQL
TOTVS LINHA RM TREINAMENTO SQLFábio Delboni
 
Sql básico - Teoria e prática: Um grande resumo
Sql básico - Teoria e prática: Um grande resumoSql básico - Teoria e prática: Um grande resumo
Sql básico - Teoria e prática: Um grande resumoHelder Lopes
 
Aula5 normalização
Aula5   normalizaçãoAula5   normalização
Aula5 normalizaçãoMatias Silva
 
Fundamentos de SQL - Parte 4 de 8
Fundamentos de SQL - Parte 4 de 8Fundamentos de SQL - Parte 4 de 8
Fundamentos de SQL - Parte 4 de 8Emiliano Barbosa
 
Treinamento de SQL Básico
Treinamento de SQL BásicoTreinamento de SQL Básico
Treinamento de SQL BásicoIgor Alves
 

Tendances (20)

Aprofundamento de DDL e DML
Aprofundamento de DDL e DMLAprofundamento de DDL e DML
Aprofundamento de DDL e DML
 
Apostila rcmdr 17 01-2013
Apostila rcmdr 17 01-2013Apostila rcmdr 17 01-2013
Apostila rcmdr 17 01-2013
 
R comamnder pdf
R comamnder pdfR comamnder pdf
R comamnder pdf
 
Aula 11 banco de dados
Aula 11   banco de dadosAula 11   banco de dados
Aula 11 banco de dados
 
Normalização - Banco de Dados
Normalização - Banco de DadosNormalização - Banco de Dados
Normalização - Banco de Dados
 
Aula10 sql-ddl
Aula10 sql-ddlAula10 sql-ddl
Aula10 sql-ddl
 
Consultas SQL
Consultas SQLConsultas SQL
Consultas SQL
 
Fundamentos de SQL - Parte 5 de 8
Fundamentos de SQL - Parte 5 de 8Fundamentos de SQL - Parte 5 de 8
Fundamentos de SQL - Parte 5 de 8
 
Normalização de dados - Primeira forma normal
Normalização de dados - Primeira forma normalNormalização de dados - Primeira forma normal
Normalização de dados - Primeira forma normal
 
Utilizando views, stored procedures e triggers
Utilizando views, stored procedures e triggersUtilizando views, stored procedures e triggers
Utilizando views, stored procedures e triggers
 
Projeto locadora
Projeto locadoraProjeto locadora
Projeto locadora
 
Comandos DDL para o MySQL
Comandos DDL para o MySQLComandos DDL para o MySQL
Comandos DDL para o MySQL
 
Normalização básica
Normalização básicaNormalização básica
Normalização básica
 
Fundamentos de SQL - Parte 6 de 8
Fundamentos de SQL - Parte 6 de 8Fundamentos de SQL - Parte 6 de 8
Fundamentos de SQL - Parte 6 de 8
 
Sql com sql server básico - Bóson treinamentos
Sql com sql server básico - Bóson treinamentosSql com sql server básico - Bóson treinamentos
Sql com sql server básico - Bóson treinamentos
 
TOTVS LINHA RM TREINAMENTO SQL
TOTVS LINHA RM TREINAMENTO SQLTOTVS LINHA RM TREINAMENTO SQL
TOTVS LINHA RM TREINAMENTO SQL
 
Sql básico - Teoria e prática: Um grande resumo
Sql básico - Teoria e prática: Um grande resumoSql básico - Teoria e prática: Um grande resumo
Sql básico - Teoria e prática: Um grande resumo
 
Aula5 normalização
Aula5   normalizaçãoAula5   normalização
Aula5 normalização
 
Fundamentos de SQL - Parte 4 de 8
Fundamentos de SQL - Parte 4 de 8Fundamentos de SQL - Parte 4 de 8
Fundamentos de SQL - Parte 4 de 8
 
Treinamento de SQL Básico
Treinamento de SQL BásicoTreinamento de SQL Básico
Treinamento de SQL Básico
 

Similaire à 07 procedures-curso gxxbr

Apostila supervisorio indusoft ind371
Apostila supervisorio indusoft ind371Apostila supervisorio indusoft ind371
Apostila supervisorio indusoft ind371Sandra Rocha
 
Sistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsSistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsPedro De Almeida
 
Apostila: Curso de java III
Apostila: Curso de java IIIApostila: Curso de java III
Apostila: Curso de java IIIVerônica Veiga
 
Trabalho de sistemas operativos
Trabalho de sistemas operativosTrabalho de sistemas operativos
Trabalho de sistemas operativosFrank macoo
 
Aula modelagem de dados
Aula modelagem de dadosAula modelagem de dados
Aula modelagem de dadosGabriel Moura
 
lista de exercícios de estrutura de dados Básico primeira prova
lista de exercícios de estrutura de dados Básico primeira prova lista de exercícios de estrutura de dados Básico primeira prova
lista de exercícios de estrutura de dados Básico primeira prova Rogério Cardoso
 
modelagem sistema da informação Unid 4
modelagem sistema da informação Unid 4modelagem sistema da informação Unid 4
modelagem sistema da informação Unid 4spawally
 
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...Bruno Rossetto Machado
 
Lista exercicios algoritmos
Lista exercicios algoritmosLista exercicios algoritmos
Lista exercicios algoritmosslashmelhor
 
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsEmacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsJosé Martins da Nobrega Filho
 

Similaire à 07 procedures-curso gxxbr (20)

Apostila supervisorio indusoft ind371
Apostila supervisorio indusoft ind371Apostila supervisorio indusoft ind371
Apostila supervisorio indusoft ind371
 
Sistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsSistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e Threads
 
Sap – stablility and abstract principle
Sap – stablility and abstract principleSap – stablility and abstract principle
Sap – stablility and abstract principle
 
Apostila: Curso de java III
Apostila: Curso de java IIIApostila: Curso de java III
Apostila: Curso de java III
 
Trabalho de sistemas operativos
Trabalho de sistemas operativosTrabalho de sistemas operativos
Trabalho de sistemas operativos
 
Aula modelagem de dados
Aula modelagem de dadosAula modelagem de dados
Aula modelagem de dados
 
Excel VBA: Aula 2
Excel VBA: Aula 2Excel VBA: Aula 2
Excel VBA: Aula 2
 
Dfd
DfdDfd
Dfd
 
Síntese do Fórum do livro-apf Outubro
Síntese do Fórum do livro-apf  OutubroSíntese do Fórum do livro-apf  Outubro
Síntese do Fórum do livro-apf Outubro
 
CURSO JAVA 01
CURSO JAVA 01CURSO JAVA 01
CURSO JAVA 01
 
Introdução ao BD Postgre
Introdução ao BD PostgreIntrodução ao BD Postgre
Introdução ao BD Postgre
 
lista de exercícios de estrutura de dados Básico primeira prova
lista de exercícios de estrutura de dados Básico primeira prova lista de exercícios de estrutura de dados Básico primeira prova
lista de exercícios de estrutura de dados Básico primeira prova
 
Academia ABAP
Academia  ABAPAcademia  ABAP
Academia ABAP
 
Crud
CrudCrud
Crud
 
S.o aula 1920
S.o aula 1920S.o aula 1920
S.o aula 1920
 
modelagem sistema da informação Unid 4
modelagem sistema da informação Unid 4modelagem sistema da informação Unid 4
modelagem sistema da informação Unid 4
 
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...
Tomada de decisões com xPaaS aplicada ao fantasy game oficial do campeonato b...
 
Lista exercicios algoritmos
Lista exercicios algoritmosLista exercicios algoritmos
Lista exercicios algoritmos
 
Por que PostgreSQL?
Por que PostgreSQL?Por que PostgreSQL?
Por que PostgreSQL?
 
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsEmacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
 

Plus de Cristiano Rafael Steffens

CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and video
CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and videoCONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and video
CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and videoCristiano Rafael Steffens
 
A pipelined approach to deal with image distortion in computer vision - BRACI...
A pipelined approach to deal with image distortion in computer vision - BRACI...A pipelined approach to deal with image distortion in computer vision - BRACI...
A pipelined approach to deal with image distortion in computer vision - BRACI...Cristiano Rafael Steffens
 
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGES
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGESA CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGES
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGESCristiano Rafael Steffens
 
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...Cristiano Rafael Steffens
 
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...Cristiano Rafael Steffens
 
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...Cristiano Rafael Steffens
 
FPGA-based sensor integration and communication protocols for automated
FPGA-based sensor integration and communication protocols for automatedFPGA-based sensor integration and communication protocols for automated
FPGA-based sensor integration and communication protocols for automatedCristiano Rafael Steffens
 
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire Detection
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire DetectionLars 2016 A Texture Driven Approach for Visible Spectrum Fire Detection
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire DetectionCristiano Rafael Steffens
 
ICRA 2016 - Interactive section Presentation
ICRA 2016 - Interactive section PresentationICRA 2016 - Interactive section Presentation
ICRA 2016 - Interactive section PresentationCristiano Rafael Steffens
 
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...Cristiano Rafael Steffens
 
Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Cristiano Rafael Steffens
 
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...Cristiano Rafael Steffens
 
Automated control module based on VBM for shipyard welding applications: Stud...
Automated control module based on VBM for shipyard welding applications: Stud...Automated control module based on VBM for shipyard welding applications: Stud...
Automated control module based on VBM for shipyard welding applications: Stud...Cristiano Rafael Steffens
 
An Unconstrained Dataset for Non-stationary Video Based Fire Detection
An Unconstrained Dataset for Non-stationary Video Based Fire DetectionAn Unconstrained Dataset for Non-stationary Video Based Fire Detection
An Unconstrained Dataset for Non-stationary Video Based Fire DetectionCristiano Rafael Steffens
 
Introdução ao processamento de imagens com OpenCV (cont)
Introdução ao processamento de imagens com OpenCV (cont)Introdução ao processamento de imagens com OpenCV (cont)
Introdução ao processamento de imagens com OpenCV (cont)Cristiano Rafael Steffens
 
Um Sistema De Detecção De Fogo Baseado Em Vídeo
Um Sistema De Detecção De Fogo Baseado Em VídeoUm Sistema De Detecção De Fogo Baseado Em Vídeo
Um Sistema De Detecção De Fogo Baseado Em VídeoCristiano Rafael Steffens
 
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)Um sistema de detecção de chamas utilizando RF e SVM (Short Version)
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)Cristiano Rafael Steffens
 

Plus de Cristiano Rafael Steffens (20)

CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and video
CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and videoCONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and video
CONVOLUTIONAL NEURAL NETWORKS: The workhorse of image and video
 
A pipelined approach to deal with image distortion in computer vision - BRACI...
A pipelined approach to deal with image distortion in computer vision - BRACI...A pipelined approach to deal with image distortion in computer vision - BRACI...
A pipelined approach to deal with image distortion in computer vision - BRACI...
 
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGES
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGESA CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGES
A CNN BASED MODEL TO RESTORE ILL EXPOSED IMAGES
 
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...
Can Exposure, Noise and Compression affect Image Recognition? An Assessment o...
 
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...
MODELAGEM DAS DINÂMICAS DA FORMAÇÃO DA GOTA E TRANSFERÊNCIA DE MASSA EM PROCE...
 
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...
UMA ABORDAGEM COMPARATIVA ENTRE MICROCONTROLADORES: ARDUINO MEGA X ARDUINO DU...
 
FPGA-based sensor integration and communication protocols for automated
FPGA-based sensor integration and communication protocols for automatedFPGA-based sensor integration and communication protocols for automated
FPGA-based sensor integration and communication protocols for automated
 
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire Detection
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire DetectionLars 2016 A Texture Driven Approach for Visible Spectrum Fire Detection
Lars 2016 A Texture Driven Approach for Visible Spectrum Fire Detection
 
Php Math and arrays
Php Math and arraysPhp Math and arrays
Php Math and arrays
 
ICRA 2016 - Interactive section Presentation
ICRA 2016 - Interactive section PresentationICRA 2016 - Interactive section Presentation
ICRA 2016 - Interactive section Presentation
 
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...
Vision-Based System for Welding Groove Measurements for Robotic Welding Appli...
 
Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)
 
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...
Welding Groove Mapping: Image Acquisition and Processing on Shiny Surfaces - ...
 
Automated control module based on VBM for shipyard welding applications: Stud...
Automated control module based on VBM for shipyard welding applications: Stud...Automated control module based on VBM for shipyard welding applications: Stud...
Automated control module based on VBM for shipyard welding applications: Stud...
 
An Unconstrained Dataset for Non-stationary Video Based Fire Detection
An Unconstrained Dataset for Non-stationary Video Based Fire DetectionAn Unconstrained Dataset for Non-stationary Video Based Fire Detection
An Unconstrained Dataset for Non-stationary Video Based Fire Detection
 
Introdução ao processamento de imagens com OpenCV (cont)
Introdução ao processamento de imagens com OpenCV (cont)Introdução ao processamento de imagens com OpenCV (cont)
Introdução ao processamento de imagens com OpenCV (cont)
 
Introdução OpenCV (Pt-Br) com exemplos
Introdução OpenCV (Pt-Br) com exemplosIntrodução OpenCV (Pt-Br) com exemplos
Introdução OpenCV (Pt-Br) com exemplos
 
Um Sistema De Detecção De Fogo Baseado Em Vídeo
Um Sistema De Detecção De Fogo Baseado Em VídeoUm Sistema De Detecção De Fogo Baseado Em Vídeo
Um Sistema De Detecção De Fogo Baseado Em Vídeo
 
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)Um sistema de detecção de chamas utilizando RF e SVM (Short Version)
Um sistema de detecção de chamas utilizando RF e SVM (Short Version)
 
G xserver curso-actualizgxxev1
G xserver curso-actualizgxxev1G xserver curso-actualizgxxev1
G xserver curso-actualizgxxev1
 

07 procedures-curso gxxbr

  • 1.
  • 2. Procedimentos: Definem processos não interativos de consulta e atualização da base de dados. Os procedimentos podem gerar um arquivo formato PDF, mediante o qual é possível listar informação na tela ou impressora. 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 de dados, mas algo um pouco mais complexo, o business component, por meio do qual serão realizados atualizações a base de dados em qualquer objeto GeneXus. Portanto, utilizando variáveis de tipo de dados business component, poderão ser realizadas atualizações incluso nos objetos que por natureza não oferecem esta possibilidade, como as web panels.
  • 3. Definição procedural A diferença das regras das transações onde as especificações se realizam de forma declarativa e GeneXus determina no momento de gerar o programa a seqüência de execução, nos procedimentos as 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 de controle, de impressão, de acesso a base de dados, etc. Definição sobre a base de conhecimento A grande potencia da linguagem dos procedimentos está que as definições são realizadas sobre a base de conhecimento e não diretamente sobre o modelo f sico (tabelas, ndices, etc.). Isto nos permite utilizar autom ticamente todo o conhecimento já incorporado ou gerado por GeneXus a partir das especificações realizadas. Por exemplo, se desejamos mostrar o resultado de uma f rmula é suficiente nomear o atributo f rmula no lugar adequado e GeneXus dispara o c lculo mostrando o resultado, sem necessidade do analista oferecer nenhuma outra informação. A informação de como se calcula um atributo f rmula est contida na base de conhecimento. Também podemos utilizar o conceito de tabela estendida, já que GeneXus conhece as relações entre as tabelas da base de dados, o analista não precisa explicitar estas relações na hora de recuperar dados. Independência da base de dados: definição a nível de atributos A definição dos procedimentos se faz a nível de atributos: não é necessário indicar expl citamente quais tabelas ser ndices. Somente mencionando os atributos que deseja acessar é suficiente para que o GeneXus determine esta informação. Isto é possível porque GeneXus 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 nas tabelas ser gerenciado automaticamente pelo GeneXus e desta forma, para atualizar os programas alcança em grande parte das vezes, como regerar os objetos sem ter que modificar nada do programado neles.
  • 4. Para cada procedimento se pode definir: • Source: Aqu o c digo correspondente a l gica do procedimento. Também podem definir-se ao final do 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 o uso 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.
  • 5. 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 uma delas a representaremos com um Printblock. Os primeiros dois Printblocks ilustram no GeneXus tal qual as primeiras duas reas pois contem unicamente textos, linhas, retângulos. Também poderíamos ter colocado estas duas reas convertendo-as em uma e utilizando portanto um nico Printblock. O terceiro Printblock ser o correspondente da rea de dados variáveis da figura anterior, que representa 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 do pa s ao que pertence. Esta informação é a representada pelos atributos CustomerId, CustomerName e CountryName da base de conhecimento da aplicação, o terceiro Printblock conter os três controles atributo CustomerId, CustomerName e CountryName. Transformando as reas em Printblocks, o Layout do procedimento ficará como o da figura na p gina seguinte.
  • 6. O Layout de um procedimento será uma sucessão de Printblocks que não tem por que seguir a ordem em que deseja que apareçam na saída. No exemplo anterior, o mesmo procedimento teria sido impresso se houvesse especificado os Printblocks na ordem inversa (ou em qualquer ordem). Aqui simplesmente são declarados. A ordem que são executados fica determinado na seção Source que é a que contem a lógica do procedimento. A partir dali serão chamados mediante um comando especí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 do Source. No exemplo, para listar todos os clientes, o Printblock de nome “customer” deve ser chamado dentro de uma estrutura repetitiva no Source. Esta estrutura repetitiva é o comando For each que estudaremos depois.
  • 7. O Printblock é um tipo de controle v lido somente nos procedimentos, que é inserido e eliminado do Layout pelo analista, e que contem outros controles -atributos, textos, retângulos, linhas, etc.-, sendo estes 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 se utiliza para inserir os controles no Layout. De fato esta toolbox está disponível para todos os objetos GeneXus 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 Insert Printblock. Como todo controle, o Printblock possui propriedades que podem ser configuradas pelo usuário. Em particular, tem a propriedade “Name”, muito importante visto que é o identificador do Printblock. Com este 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 ou View/Properties.
  • 8. 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 de alguns comandos que veremos. O estilo de programação é procedural – imperativo – o Source será uma sucessão de comandos onde a ordem é fundamental: a ordem em que estejam especificados corresponderá, exceto exceçõ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 dentro de um loop (exit) ou abandonar o programa (return), assim como também comandos específicos desta linguagem: para imprimir um Printblock do Layout (print), para acessar a base de dados (For each), 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, podem definir-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 os comandos de controle, que são comuns a todos as linguagens de programação imperativa, os comandos de atribuição e os de impressão.
  • 9. A definição do acesso a base de dados para recuperar a informação se realiza com um único comando: o comando For each1. Usando o For each se define a informação que vai acessar. A forma de o fazer é baseada em nomear os atributos a utilizar. Assim, com este comando se definem quais atributos são necessários em qual ordem vai ser recuperada, e GeneXus se encarrega de encontrar como fazer. Não se especifica de quais tabelas se devem 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 de erro 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 a especificação do procedimento é de mais alto nível possível, de tal forma que ante mudanças na estrutura 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 ou navegada. 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 se consegue consultar a base de dados.
  • 10. Intuitivamente com este comando queremos listar identificador, nome e país de cada um dos clientes da base de dados. Ou seja, queremos percorrer à tabela CUSTOMER, e para cada cliente seja recuperado da tabela COUNTRY o nome do país ao qual pertence, imprimindo esta informação, junto com o identificador e nome do cliente. (Observar que a tabela COUNTRY pertence à estendida de CUSTOMER) Como o GeneXus infere isto, só o que fizemos foi For each do exemplo informar os atributos que nos interessava mostrar?
  • 11. Dentro de todo For each navega-se - percorre ou itera - a tabela base, mas podemos acessar as tabelas que constituem sua tabela estendida para recuperar a informação, por pertencer a estendida está relacionada com cada registro da tabela base com que esteja trabalhando em cada interação (o conceito de tabela estendida é muito importante neste comando e sugerimos repassar sua 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 tabela COUNTRY (que está na estendida de CUSTOMER). Dizemos então que se percorre CUSTOMER e se 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 ao GeneXus esta informação. Não é necessário, já que o GeneXus conhece as relações entre as tabelas, e na base os atributos mencionados dentro do For each e pode encontrar sem necessidade de mais informações uma tabela estendida que os contenha. A tabela base dessa estendida é escolhida como tabela base do For each.
  • 12. A tabela base correspondente a essa tabela estendida é chamada de tabela base do For each e será percorrida seqüencialmente, executando para cada registro o que for indicado nos comandos internos do For each.
  • 13. Para o exemplo apresentado onde queremos uma lista dos clientes: seu identificar, nome e nome de país, observamos os atributos utilizados dentro do For each, e percebemos que eles são os contidos no 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 tabelas nas quais aparecem os atributos do For each (Tools/Diagrams). Aqui podemos ver porque do requerimento da tabela estendida seja a mínima (entendendo por mínima aquela que envolve um número menor de tabelas). A tabela estendida de INVOICE também contêm todos os atributos do For each, mas não é mínima, pois a de CUSTOMER também os contêm. Portanto, se vamos percorrer seqüencialmente à tabela CUSTOMER, e para cada registro dessa tabela, 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 atributo CountryName, para poder imprimi-lo, junto com o código e nome do cliente.
  • 14. Listagem de navegação GeneXus oferece para todos os objetos uma lista conhecida como listagem de navegação, que é o resultado da especificação do objeto. Esta listagem é muito útil para os relatórios, já que indica quais são as tabelas que são acessadas em cada For each do Source, se existe um índice para recuperar os dados da tabela base, e em caso de que assim seja qual é esse índice (seu nome), se aplicam filtros 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á percorrendo a 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ão impressos), se existe um índice que satisfaça essa ordem, qual é seu nome, e aparecem mais duas informaçõ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 chave primária, e endentadas todas as tabelas da estendida que devam ser acessadas para recuperar a informação associada ao registro da tabela base que está sendo trabalhada em cada interação do For each. Neste caso se mostra somente a tabela COUNTRY. No comando For each do Exemplo não aparece explicitamente nenhuma informação referente a ordem desejada da impressão da informação do relatório. Neste caso GeneXus escolhe a ordem da chave 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 tabela CUSTOMER.
  • 15. 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 dentro de uma faixa inserida pelo usuário, então devemos agregar ao For each que havíamos visto uma cláusula where, para especificar os filtros desejados sobre os dados: For each where (CustomerName >= &Start) and (CustomerName <= &End) print customer Endfor onde as variáveis &Start e &End devem ser definidas no procedimento com o mesmo tipo de dados que CustomerName, 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 tabela base, 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 ter programando 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ção booleana 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 da seguinte forma: os filtros estabelecidos pelo where são aplicados somente quando o when é satisfeito. Isto é lido da 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 os clientes (como se não existissem os comandos where). Cada condição booleana de um “where” pode estar composta de várias expressões booleanas concatenadas com 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.
  • 16. Listagem de navegação Aparece um novo elemento nesta listagem que não existia, quando não tínhamos cláusulas where: os constraints (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 ICUSTOMER correspondente • 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 estiver vazio) e somente caso se cumpra, executar para esse cliente os comandos que aparecem dentro do For 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)
  • 17. 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 serem recuperados utilizando o atributo CountryName, que é da tabela COUNTRY, pertencente à tabela estendida de CUSTOMER. Neste exemplo nada foi feito em relação à ordem, os dados aparecerão ordenados pela chave primária da tabela base, ou seja, pelo identificador de cliente, CustomerId. .
  • 18. Se queremos realizar uma lista de todos os clientes, ordenado por nome do cliente ao invés do có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 GeneXus indicará na listagem de navegação mediante uma advertência (“warning”) que não existe um índice para satisfazer a ordem, o que pode ocasionar problemas de performance, dependendo da plataforma 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 traduz numa 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 ser condicional,como o exemplo dois. Caso a condição when não for cumprida, essa ordem não será utilizada e não existir ordem incondicional (sem a cláusula when) como no exemplo, a ordem será indefinida, isto é, a ordem poderá 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 arquiteturas cliente/servidor e uma sem condição (a última da lista). O primeiro comando order cuja condição do when 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 da chave 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 ordem em particular e delega esta tarefa ao DBMS. A cláusula order none pode ter condição (when).
  • 19. Listagem de navegação Quando não existe um índice que satisfaça o ordem de um For each, como é o caso do Exemplo, o analista 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 maior processamento 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 de usuário), portanto deve-se estudar, caso por caso, a solução particular levando em consideração a plataforma 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 posteriormente decide-se fazê-lo, somente é preciso que o relatório seja gerado novamente (sem modificar nada do que 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 For each (neste caso, o comando print)
  • 20. Se queremos filtrar os clientes por determinada faixa de nomes, o primeiro exemplo, como não foi especificada 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, e para cada registro da mesma deve-se analisar se o registro cumpre ou não as condições (restrições ou “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 nos filtros estabelecemos que queremos somente aqueles clientes cujo nome, CustomerName, esteja na faixa determinada, já não sendo necessário recorrer toda a tabela base para obter os dados que cumprem 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 que seja criado um índice temporário em execução para resolver a consulta se o DBMS não pode fazer de 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
  • 21. A listagem de navegação nos informa que a consulta está otimizada já que percorre somente os registros 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 ou condições explícitas por igualdade, se busca se existe um índice que contenha os atributos das condições mais os do Order. A condição explícita prevalece sobre a implícita para a determinaçã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 que dito í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 determinado pelos atributos do índice. •Se não existe um índice que corresponda com as condições, ou seja que não se pode otimizar a percorrida segundo as condições do nível, então se ordena pelos atributos da Primary Key.
  • 22. Por exemplo, se temos as transações: COUNTRY CITY { { CountryId* CountryId* } CityId* } O For each: For Each order CityId Where CountryId = 1 ... Endfor Percorre a tabela CITY, ordenando por: CountryId, CityId e utilizando o índice ICITY (índice por chave primária que contem ambos atributos). Ainda é o próprio DBMS que resolve o plano de acesso mais apropriado, a informação antes mencionada influirá em sua determinação.
  • 23. Pode ocorrer de que um For each tenha mais de uma tabela base cuja estendida contenha os atributos do For each, sendo mínima. Frente esta ambigüidade, GeneXus escolhe a “primeira” destas tabelas estendidas mínimas. Para resolver este tipo de ambigüidade surge a cláusula defined by, que permite usar atributos da tabela base desejada, que não serão utilizados para devolver a consulta ordenada por esses atributos, nem para filtrar informaçã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 atributo mais dentro do For each. Este é o caso do exemplo apresentado, não que não queremos listar todos os clientes da tabela CUSTOMER, pelo contrário, queremos listar todos os clientes das faturas. Se não utilizar nenhum atributo 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 tempo de 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 atributo secundário. Se quisermos uma listagem dos clientes e seu país, seriam equivalentes: For each For each Defined by CountryName print customer print customer Endfor 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 For each continuará sendo válido e fazendo o que queremos, o segundo deixará de funcionar, ja que no Defined By não tem nenhum atributo da tabela base.
  • 24. Podem aparecer vários atributos, no caso de um único atributo não determinar a tabela base, onde ao 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 forma eliminamos por completo toda possível ambigüidade. Isto não é obrigatório, podemos usar no Defined by para atributos primários quando notarmos que nã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 fica determinada exclusivamente a partir dos atributos mencionados no defined by. A realidade é que os atributos do defined by determinam uma ou mais tabelas base candidatas a serem a tabela base do For each, mas tendo selecionado a tabela base candidata, sua estendida contê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 For each devem estar contidos em uma mesma tabela estendida).
  • 25. O Printblock menssage (poderá ter um texto advertindo ao usuário que não existam clientes que cumpram os filtros) executa somente quando não entrar no For each, isto é, quando não tem nenhum registro 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 mais adiante. A cláusula when none deve ser a última dentro do For each. As ações a serem realizadas quando não existe nenhum registro que cumpra as condições, ficam determinadas pelo bloque de código que tem 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 executados somente no caso em que a tabela base do For each esteja vazia, porque somente nesse caso não haverá 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 levados em 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 com respeito ao For each que contêm o When none, já que são considerados dos For eachs paralelos.
  • 26. 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 de conhecimento escrito simples, ou entre parênteses. Quando um atributo do order aparece entre parê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 última listada. Respondendo ao fato de que somente uma dessas cláusulas order tomará efeito, se vão avaliando suas condições (as do when) até a primeira que de True, e com essa fica. Se nenhuma der true e existe uma cláusula incondicional (isto é, sem when), pega essa ordem. Se não existe tal cláusula, ou ordem será indefinido, querendo isto significa que dependerá da plataforma, e incluso poderá variar entre execuções sucessivas. A justificatova para escrever cláusulas order condicionais, deriva se quisermos aplicar cláusulas where condicionais. Isto é, por motivos de otimização das consultas. Por exemplo, se queremos filtrar por CustomerName > &Name when not &Name.IsEmpty(), então para otimizar a consulta deveríamos ordenar por CustomerName, mas se não aplicar o filtro, visto que &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.
  • 27. 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 de dados. 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 Where como 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 sua determinaçã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ão determinam. Devem examinar-se também outras partes do For each. Using DataSelectorName Permite definir filtros de acordo ao critério definido no DataSelector1 definido em DataSelectorName. Where Condition Condição booleana que deverão cumprir os dados para ser processados dentro do For each, podendo ser uma condição composta, 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 com uma condição: where cond1 where 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 nos comandos 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 se avalia 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 se está 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 do DBMS) se transformará em um filtro "comum" substituindo o WHEN por um OR. Além disso, se gerar a mensagem de código spc0053 – ‘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 de valores dos atributos referenciados. Não veremos esta cláusula. O leitor interessado pode recorrer as distintas fontes de documentação para estudá-la (Help, Wiki, Release Notes, etc.) Defined by defined_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 For each. A cláusula defined by aparece para solucionar alguns problemas de ambigüidade na determinação da tabela base (quando existem várias tabelas estendidas mínimas que contenham os atributos do For each) ou quando se deseja que a tabela base seja outra, diferente da que seria determinada pelos atributos que aparecem no resto do For each (este caso tem sentido quando se estude “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 atributos determinam tabela como a candidata a tabela base, mas se depois os outros atributos do For each não estão contido na estendida 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 o chamaremos 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.
  • 28. Os comandos especificados serão executados seqüencialmente para os dados da tabela estendida que cumpram as Condições de filtro, considerando os dados na ordem especificado. Blocking Este tema será abordado mais adiante do curso, mas a idéia geral é que a especificação desta clásula permite realizar atualizações e eliminações em blocos, reduzindo assim o número de acesso a base de dados. When Duplicate Esta 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 a unicidade 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 none Em caso de que não existam dados que cumpram as Condições de filtro não será executado os comandos do code1 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 dos dois, 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).
  • 29. Os code snippets são moldes de c digo que GeneXus tem predefinido, que nos ajudam a escrever o c digo fonte. Quando estamos trabalhando no Source de um procedimento, a Toolbox 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 seja mais r pida todav a. Por exemplo, digitando simplesmente fe se escreve autom icamente o seguinte 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)
  • 30. 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 For eachs 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 aninhados porque 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 registro da 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 tabelas INVOICE e BILL (recibo) respectivamente. Temos definido dois For eachs paralelos. O primeiro percorre todas as faturas e o segundo todos os recibos.
  • 31. O For each é uma estrutura repetitiva, que permite recuperar muitos registros de uma tabela. Quando pensamos em For eachs aninhados, é evidente que o que buscamos recuperar é, para cada registro do principal,muitos registros do aninhado. O que o GeneXus detecta que se quer fazer com este tipo de estruturas, de forma de inferir o comportamento 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 um atributo ou conjunto de atributos e para cada grupo, recuperar alguns registros: os correspondentes ao grupo. 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 eachs aninhados, 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 imprimiremos detalhe de cada uma, devemos navegar por duas tabelas: INVOICE (que armazena os cabeçalhos) e INVOICEDETAIL (que armazena as linhas), e o faremos de uma forma bem simples, sem colocar o nome 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 seus dados pessoais, os dados de todas suas faturas. Este comportamento se dá com um par de For eachs aninhados, onde o primeiro navega pela tabela CUSTOMER e o segundo navega pela tabela INVOICE, recuperando somente as faturas desse cliente, como veremos em seguida.
  • 32. Se queremos realizar uma lista de todas as faturas do sistema, onde para cada uma se mostre tanto a informação do cabeçalho como das linhas. No Source programado, percorremos à tabela INVOICE, imprimindo os atributos que nos interessam do cabeçalho e para cada registro dessa tabela, percorremos a tabela INVOICEDETAIL, para imprimir os atributos que nos interessam de suas linhas. Podemos perceber o quão simples é esse processo, simplesmente utilizando os atributos que queremos usar, ficando o GeneXus encarregado do resto. Observemos que nem sequer tivemos que especificar a condição de filtro sobre os registros de INVOICEDETAIL a recuperar. O GeneXus se dá conta da relação existente entre as tabelas, e aplica automaticamente 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ão precisa que especificá-la).
  • 33. Como para um For each simples, o GeneXus deve determinar para cada For each (principal e aninhado) 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. Aqui ficaremos com idéia intuitiva de que o faz de forma similar como o fazia no caso de um For each simples. 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: infere também na aplicação da condição sobre os dados de INVOICEDETAIL que indicamos acima.
  • 34. Quando temos dois For eachs aninhados,GeneXus deve determinar a tabela base de cada um, e essas 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 do mesmo. Entre esses comandos, encontra-se o For each interno, que será executado, como qualquer outro 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 each principal, mas as determinações não são por completo independentes, como se pode pensar equivocadamente. A partir da determinação das tabelas base de cada For each e das relações que encontre o GeneXus entre as tabelas envolvidas, surgem três possíveis casos de For eachs aninhados, que correspondem aos casos enunciados anteriormente: join, Produto cartesiano e corte de controle, respectivamente. Estudaremos cada um desses casos com exemplos.
  • 35. 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 encontra a mínima tabela estendida que os contenha e define assim a tabela base através da qual chega a todas as outras. • Para determinar da tabela base do for each aninhado, GeneXus fixa os atributos utilizados dentro do corpo do mesmo, onde estão incluídos ou dentro da tabela estendida previamente determinada (a do For each principal). Em caso afirmativo, GeneXus determina que a tabela base do For 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 do For each aninhado e que tenha alguma relação com a tabela base do For each principal. A tabela base 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 cumpre que contenha os atributos, finalmente a escolhe, mas sempre busca a forma de encontrar relações entre ambas tabelas bases. Somente neste último caso de não se encontrar relações, se procede a determinar a tabela base como se fosse For eachs independentes. Estudaremos um esquema resumindo o anterior depois.
  • 36. 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 de INVOICE (que é a tabela base do principal), então se passa a determinar sua tabela base como se explicou anteriormente: se busca a tabela estendida mínima que contenha a ProductDescription, ProductPrice, InvoiceLineQuantity e InvoiceLineAmount, e caso possível esteja reacionada com INVOICE. A tabela que cumpre ambos requisitos em INVOICEDETAIL.
  • 37. Da determinação das tabelas base, surgem os três casos de For eachs aninhados que foram mencionados e que estudaremos um a um em seguida. Este tema é de vital importância, já que a maioria das aplicações requerem navegações complexas sobre as tabelas, onde se requer uma mistura de todos estes casos.
  • 38. Este é o caso em que o GeneXus determina que as tabelas base de cada For each são distintas e tem uma 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 N relacionados 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 a ficar somente com esses registros relacionados. O exemplo do procedimento que imprime todas as faturas do sistema, com seus detalhes, cai dentro desta categoria. Nesse caso tem uma relação 1-N direta entre as tabelas que se percorre: para cada cabeçalho da fatura, lista-se o mesmo, junto com todas suas linhas da fatura, ou seja, todos os registros 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 para cada registro da mesma, percorrer outra tabela, relacionada com a primeira por uma relação N-1. O GeneXus 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, e a do segundo, INVOICE. Como encontra atributo em comum entre a tabela estendida do For each principal e a tabela base do aninhado1, CustomerId, determina que esse atributo atue como condiçã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ção direta ou indireta 1-N entre as tabelas base. A relação será direta quando a tabela base do principal tenha relação 1-N com a tabela base do aninhado, isto é, seja superordinada desta última. A relação será indireta quando isto não exista uma relação direta entre as tabelas base, mas sim entre a tabela estendida do primeiro e a tabela base do segundo. Também será indireta quando a tabela estendida do aninhado inclua a tabela base do principal. Veremos exemplos em seguida.
  • 39. Vejamos, como o GeneXus faz para determinar as tabelas base. Os atributos utilizados no For each externo 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 each principal,não os do aninhado. Depois, GeneXus deve encontrar a tabela base do For each aninhado. Os atributos que participam sã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 era CUSTOMER. Portanto passa a determinar sua tabela base como a de qualquer For each simples: a tabela estendida INVOICE contem todos os atributos do For each aninhado, e é a mínima tabela estendida que os contenha. Portanto, INVOICE será escolhida como tabela base do segundo For each. Observemos, novamente, que não explicitamos cláusula where no For each aninhado para filtrar as faturas do cliente do For each principal. Justamente, por tratar-se de tabelas relacionadas por uma relação 1-N direta, esta condição é aplicada implicitamente pelo GeneXus e pode ser visto na listagem de navegação acima. Outro fato interessante que pode ser observado nesta lista: no For each aninhado não foi especificado a cláusula order, GeneXus não escolheu a ordem da chave primária da tabela base e sim pelo atributo da relação, CustomerId. Desta maneira, está otimizando automaticamente a consulta. 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 dito For each.
  • 40. Se queremos realizar uma listagem das faturas emitidas pelo país, teremos outro caso de For eachs aninhados 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 encontrar somente um país relacionado à mesma. Este é um caso um pouco mais complexo que o anterior, porque a tabela estendida do For each principal não tem intersecção com a tabela base do aninhado (est(COUNTRY) ∩ INVOICE = φ), mas existe 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 as faturas 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ão pode otimizar a percorrida. O leitor pode testar este caso em GeneXus e estudar detalhadamente a listagem de navegação resultante.
  • 41. Neste caso o GeneXus não encontra uma relação 1-N direta ou indireta entre as tabelas e portanto não aplica filtros implícitos aos registros do For each aninhado, ou seja, realiza um produto cartesiano entre 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 each aninhado. 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ão condições implícitas inferidas pelo GeneXus, mas sim especificadas explicitamente pelo programador. .
  • 42. No exemplo que vimos anteriormente, da listagem de clientes e suas faturas, o que acontece se um cliente não possuir faturas? Como a tabela base do For each principal é CUSTOMER, o cliente sai impresso antes de saber-se se tem 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, é porque está em uma fatura!. Mas para poder agrupar as faturas por cliente, de tal forma de poder mostrá-las desse modo, devemos percorrer a tabela INVOICE ordenada por CustomerId. Desta forma processaremos a informação de um cliente, e depois passaremos ao seguinte, para processar sua informação, e assim sucessivamente. Se imaginamos um ponteiro que se vai mostrando sequencialmente pela tabela INVOICE, podemos escrever 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 o CustomerName 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 mudou o cliente).
  • 43. 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 eachs aninhados que estão no slide acima. Comparando este código com o que vimos anteriormente para o caso de join, vemos que existem somente duas diferenças: a cláusula order que aparece neste código, junto com o defined by. Somente com essas mudanças da lista original, mudamos radicalmente o comportamento, neste caso somente serã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 funcione como 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 each principal,mas sim uma cláusula order. A cláusula order é indispensável, porque é ela que especifica por qual atributo ou conjunto de atributos 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 que queremos (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 vez do defined by o comando print if detail dentro do corpo do primeiro For each (este comando diz ao GeneXus que tome como tabela base do For each, a mesma que determinar para o aninhado).
  • 44. 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 do segundo 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 algum atributo 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.
  • 45. Exemplo: Controle de corte duplo Vamos supor que queremos como antes listar os clientes e suas faturas, mas queremos agrupar as faturas de cada cliente por data. Isto é, queremos mostrar, para cada cliente, para cada data, as faturas existentes. Exemplo: Customer: 1 João Silveira Date: 12/05/05 Invoice Id Invoice Amount 1 15 Date: 01/01/06 Invoice Id Invoice Amount 9 35 3 30 Customer: 3 Maria Silva Date: 06/06/05 Invoice Id Invoice Amount 2 20 Date: 12/08/05 Invoice Id Invoice Amount 4 40 8 15 Date: 02/02/06 Invoice Id Invoice Amount 7 20 … Como agora queremos agrupar por cliente, e dentro desse grupo por data de fatura, necessitamos três For eachs aninhados: For each order CustomerId defined by InvoiceDate print customer For each order InvoiceDate print date For each print invoice Endfor Endfor Endfor Como exercício, vamos seguir todos os passos que realiza GeneXus para inferir o comportamento do procedimento. 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 para dentro, determinando de cada For each, sem levar em consideração os atributos dos For eachs internos ao que se está considerando.
  • 46. 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 eachs sobre 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 somente um 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, agrupar por InvoiceDate, então teremos que ordenar o primeiro For each por CustomerId e ou imediatamente aninhado por InvoiceDate. No exemplo estamos dizendo que: Enquanto não encontrar o final da tabela Imprimir os dados do cliente da fatura atual Enquanto não mude o cliente Imprimir a data da fatura atual Enquanto não mude a data Imprimir os dados da fatura atual (Id e Amount) Avançar o ponteiro ao seguinte registro !" # $ $ $ % " # " ! " "&!' "(! " # ' # " &" " &!) " " * + " # # "# & ", !" # - $ $ $ % " # " ! " "&!' "(! " # ' # " &" " &!) " " * + " # # "# & ", - $ $ $ . # " " " " ! " "&!' "(! " # ' * /) # & " (! " #, "0 1
  • 47. Recomendamos programar em GeneXus este procedimento e observar cautelosamente a listagem de navegação. Verá que GeneXus escolhe uma única ordem, quando não tem um índice criado: o composto pela concatenação das ordens de cada For each com cláusula order. Este resultado é claro se pensarmos que um único ponteiro vai se deslocando pela tabela base. Uma vez determinado a Order do Controle de Corte se otimiza, buscando o melhor índice levando em 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ível aninhado, vendo de fora para dentro: primeiro determina-se a tabela base do For each mais externo, depois o que está aninhado a este e assim sucessivamente. Determinação da Tabela Base do For Each Externo Determina 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ão participam os atributos que estão dentro do When none, no caso do For each principal ter esta cláusula. Como no caso de um For each simples, que se encontra a mínima tabela estendida que contenha ditos atributos. Determinação da Tabela Base do For Each Aninhado Podemos chegar a pensar por analogia que deveríamos extrair os atributos do For each aninhado, e fazer o mesmo que antes, ou seja, encontrar a mínima tabela estendida que contenha esses atributos, 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 mesmo estão incluídos ou não dentro da tabela estendida previamente determinada. Em caso afirmativo, o GeneXus determina que a tabela base do For each aninhado será a mesma que a do For each principal ( e será um caso de controle de corte) Caso contrário, se determina da seguinte maneira: busca a mínima tabela estendida que contenha a todos os atributos do For each aninhado, tratando de encontrar aquela que tenha alguma relação com a tabela base do For each principal. Se não encontra uma tabela estendida que contenha a todos os atributos do For each aninhado e que além desta relacionada, fica com a tabela estendida mínima que contenha os atributos ainda que não tenha relação.
  • 48. Os comandos introduzidos são similares aos existentes nas linguagens de Programação imperativa conhecidas, por isso não incluímos a documentação deste tema. Pode ser encontrada no curso não presencial ou no Help do GeneXus. Os dois últimos, incorporam alguns elementos importantes sobre administrar 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 se ingressa ao loop, até o valor fim que toma a mesma quantidade de interações. De interação em interação a variável &var vai incrementando automaticamente numa quantidade igual a passo. O valor 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 de interação em interação. Exemplo For &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 de dados estruturado (SDT).
  • 49. 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 ou mais 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 = 1 do 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 um Procedure: 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 valor de &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 uma variá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 se chame 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.
  • 50. Aqui veremos alguns comandos de impressão, que permitem desenhar a saída do procedimento. Print Onde nomePrintBlock é o identificador de um Printblock do Layout. Não existindo no Layout um Printblock com esse nome, ao tentar salvar o objeto mostra-se uma mensagem de error informando sobre esta situaçã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 em qualquer 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 desejamos imprimir contêm atributos. A nica exceção desta regra se produz quando os atributos do Printblock est incluídos entre os parâmetros recebidos pelo procedimento, pois neste caso não é necessário acessar a base de dados para recuperar seus valores, visto que já vem instanciados. Header Aqu 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 um dos 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: Header Print title End Onde title é o nome de um Printblock do Layout que contem este texto.
  • 51. Também poder amos ter escrito diretamente: Print title no início do Source, mas neste caso, se a listagem tem várias p ginas, somente sairá impresso este texto na primeira. No outro caso, sairá em cada uma das p ginas, como cabeçalho. Footer Define 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 endOfPageText end onde endOfPageText é o nome de um Printblock do Layout
  • 52. Desenho da saída Existem alguns comandos para desenhar a saída do procedimento. Apresentamos aqui alguns efeitos da documentação. MT nlines: nlines é o número de linha em que se quer começar a imprimir a listagem. Caso não seja especificado 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úmero especificado menos a margem de baixo (valor por default é 6). Ex: PL 66 Seta o tamanho da página a 66 linhas, ainda que somente 60 linhas sejam impressas no form, com uma 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 um salto de página). Lineno nlines: Define o número de linha onde vai ser impressa a seguinte linha. Se o número de linha atual é maior ao número especificado, então, a linha será impressa na próxima página. O de linhas 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 entre duas linhas, este comando as imprimirá na mesma linha.
  • 53. Em Web as listagens somente podem ser PDF e devem ser configuradas as propriedades e regras anteriores 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 de todos os objetos chamados direta ou indiretamente por ele. O programa executável gerado pode compilar e executar de forma independente, isto é, ao selecionar 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 configurando a propriedade Main program do mesmo com valor True.
  • 54. 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) com uma diferença: enquanto a cláusula “where” está ligada à um For each específico - aquele ao que pertence -, 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-se algum dos atributos que interferem numa “condição”, então a mesma pode ser aplicada à este For each 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 cada condição das especificadas na seção “Conditions”. Se no Source do procedimento “PrintCustomers” temos: For each Print customer Endfor Então ao especificar as condições que se mostram no slide, estaremos filtrando os clientes, de acordo com as condições (é equivalente ter as condições como “where”).
  • 55. 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 aplicam somente aos For eachs para os que tem sentido aplicá-las. Na tabela estendida do último For each não se trabalha com nome de cliente, nem com identificador de fatura. Não tem sentido aplicar as condiçõ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ção Os atributos envolvidos nas “condições” não participam na determinação das tabelas base dos For eachs 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 determinar a 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 igualdade para os For eachs que tenha sentido, mas não participam na determinação das tabelas base.
  • 56. Resumimos aqui as distintas formas de filtrar em um procedimento a informação da base de dados a ser recuperada: a. cláusulas where b. condições c. 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 os filtros especificados como condições ou os que ficam determinados pelos atributos na regra parm são globais, 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 o mesmo valor que o recebido por parâmetro. Por outro lado, os filtros especificados nas cláusulas where de 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 tabela base 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.