You are on page 1of 409

Introdução Teórica

1

Ferramentas e Metodologias

Nossa tarefa como profissionais de informática consiste em desenvolver e manter aplicações para apoiar ao usuário na sua atividade. Para realizar esta tarefa existem diferentes ferramentas e metodologias. GeneXus é uma ferramenta para o desenvolvimento de aplicações sobre bases de dados. Seu objetivo é permitir a implantação de aplicações no menor tempo e com a melhor qualidade possível. Em linhas gerais, o desenvolvimento de uma aplicação implica tarefas de análise, desenho e implementação. A maneira do GeneXus alcançar o objetivo anterior é liberar as pessoas das tarefas automatizáveis (como o desenho da base de dados), permitindo assim se concentrar nas tarefas realmente difíceis e não automatizáveis (como compreender os problemas do usuário). GeneXus emprega uma metodologia que tem um enfoque muito diferente das metodologias mais utilizadas. Aprender a utilizar GeneXus adequadamente vai além de conhecer uma nova linguagem: o mais importante é aprender sua metodologia.

2

Modelo da realidade
A partir das visões dos usuários

Satisfaz
MODELO DA REALIDADE

Engenharia Reversa

BASE DE DADOS

PROGRAMAS

VISÕES DE USUÁRIOS

O primeiro problema enfrentado no desenvolvimento de aplicações é a obtenção do conhecimento da realidade. Ninguém dentro da empresa conhece os requerimentos e o alcance da aplicação para desenvolver toda a aplicação. Então, como fazer para obter o conhecimento da realidade de uma forma suficientemente objetiva e detalhada ao mesmo tempo, que nos permita construir um modelo corporativo? Este conhecimento se encontra em cada uma das visões dos usuários. Cada usuário conhece bem os objetos que trabalha cotidianamente, a informação que ele gerencia, as regras que devem ser seguidas, os cálculos que devem ser realizados. O ponto de partida da metodologia GeneXus é: descrever as visões dos usuários para modelar o sistema; e a partir da definição da realidade do modelo, o GeneXus constrói o suporte computacional - base de dados e programas - de forma totalmente automática.

3

Desenvolvimento com GeneXus

REALIDADE
DESCRIÇÃO DE OBJETOS

Utilizando GeneXus, a tarefa básica do analista é a descrição da realidade. Somente o homem pode desenvolver esta tarefa, já que só ele pode entender o problema do usuário. O analista GeneXus trabalha em alto nível, em vez de realizar tarefas de baixo nível como: desenhar arquivos, normalizar, desenhar programas, programar, buscar e eliminar os erros dos programas. Para começar o desenvolvimento de uma aplicação com GeneXus, primeiramente deve ser criado um novo projeto ou base de conhecimento. Uma vez criada uma nova base de conhecimento (em inglês é: knowledge base; abreviado: KB), o seguinte passo é descrever as visões dos usuários. Para isso, os objetos da realidade (prestando atenção aos substantivos que os usuários mencionam em suas descrições, como por exemplo: clientes, produtos, faturas) e passar a defini-los mediante objetos GeneXus. Com a definição destes objetos, o GeneXus pode extrair o conhecimento, desenhar a base de dados e os programas da aplicação em forma totalmente automática.

4

Desenvolvimento com GeneXus

REALIDADE
DESCRIÇÃO DE OBJETOS

BASE DE CONHECIMENTO

Utilizando GeneXus, a tarefa básica do analista é a descrição da realidade. Somente o homem pode desenvolver esta tarefa, já que só ele pode entender o problema do usuário. O analista GeneXus trabalha em alto nível, em vez de realizar tarefas de baixo nível como: desenhar arquivos, normalizar, desenhar programas, programar, buscar e eliminar os erros dos programas. Para começar o desenvolvimento de uma aplicação com GeneXus, primeiramente deve ser criado um novo projeto ou base de conhecimento. Uma vez criada uma nova base de conhecimento (em inglês é: knowledge base; abreviado: KB), o passo seguinte é descrever as visões dos usuários. Para isso, os objetos da realidade (prestando atenção aos substantivos que os usuários mencionam em suas descrições, como por exemplo: clientes, produtos, faturas) e passar a defini-los mediante objetos GeneXus. Com a definição destes objetos, o GeneXus pode extrair o conhecimento, desenhar a base de dados e os programas da aplicação em forma totalmente automática.

5

Desenvolvimento com GeneXus
REALIDADE

DESCRIÇÃO DE OBJETOS

BASE DE DADOS

BASE DE CONHECIMENTO

PROGRAMAS

A partir dos objetos definidos na base de conhecimento, GeneXus gera automaticamente tanto os programas de criação/reorganização da base de dados como os programas da aplicação. Depois, se um objeto da realidade muda, são identificadas as novas ou diferentes características acerca do mesmo, ou encontrando objetos ainda não modelados. O analista GeneXus deve refletir sobre as mudanças correspondentes nos objetos GeneXus e a ferramenta se encarrega automaticamente de realizar as modificações necessárias tanto na base de dados como nos programas associados. A metodologia GeneXus é uma metodologia incremental, pois, parte da base da construção de um sistema mediante realizações sucessivas. Em cada momento, o analista GeneXus define o conhecimento que tem e assim que passa a ter mais conhecimento (ou simplesmente um conhecimento diferente), reflete na base de conhecimento, e o GeneXus se ocupa de fazer automaticamente todas as adaptações na base de dados e nos programas. Se GeneXus não for capaz de realizar automaticamente as modificações na base de dados e nos programas, conforme sejam realizadas as mudanças que assim o requerem, o desenvolvimento incremental seria inviável

6

Alguns objetos GeneXus

Transações
(Trns)

Procedimentos
(Procs)

Data Providers
(DP)

Web Panels
(Wbps)

e tem mais, que veremos...

Uma vez criada uma nova base de conhecimento, o passo seguinte consiste em começar a descrever os objetos da realidade mediante objetos GeneXus. Os objetos GeneXus mais importantes são: Transações Permite definir os objetos da realidade que o usuário manipula (ex: clientes, produtos, fornecedores, faturas, etc.). São os primeiros objetos definidos, já que através das transações, GeneXus infere o desenho da base de dados. Além de ter por objetivo a definição da realidade e a conseqüente criação da base de dados normalizada, cada transação tem associada uma janela para ambiente windows e outro para ambiente Web, para permitir ao usuário inserir, eliminar e modificar de forma interativa a base de dados. O analista GeneXus decidirá se trabalha em ambiente windows, Web, ou ambos, e GeneXus gera os programas para isso. Procedimentos Permitem recuperar informação da base de dados, e será mostrada na tela, em um arquivo ou impressa em papel. São as típicas listagens ou relatórios. Além disso, permitem atualizar informação da base de dados. Data Providers Permitem carregar e devolver dados hierárquicos para troca de informação entre objetos da mesma aplicação ou de outras aplicações. Web Panels Permite ao usuário realizar interativamente consultas na base de dados, através de uma janela. Exemplo: uma web panel permite ao usuário ingressar uma faixa de caracteres, e mostra todos os clientes cujos nomes se encontram dentro dessafaixa. São objetos muito flexíveis que podem ser usados para múltiplos usos. Não permitem a atualização da base de dados, somente consultá-los.

7

Processo de desenvolvimento de uma aplicação com GeneXus
Transações
(Trns)

Procedimentos
(Procs)

Data Providers
(DP)

Web Panels
(Wbps)

Base de Conhecimento Base de Conhecimento

Base de Dados

Os primeiros objetos definidos são as transações, já que é a partir delas que o GeneXus extrai o conhecimento necessário para desenhar o modelo de dados normalizado (em 3ª. forma normal). Depois vão se definindo os demais objetos que correspondam

8

Criação da Base de Dados Transações (Trns) Procedimentos (Procs) Data Providers (DP) Web Panels (Wbps) Base de Conhecimento Base de Conhecimento Base de Dados Programas Criação BD GeneXus gera automaticamente os programas necessários para criar a base de dados e os executa. 9 . Desta forma a base de dados é criada pelo GeneXus de forma automática.

etc) Depois. Wbps. Procs. GeneXus gera programas de aplicação para interagir com a base de dados previamente criada. 10 .Geração dos Programas da aplicação Transações (Trns) Procedimentos (Procs) Data Providers (DP) Web Panels (Wbps) Base de Conhecimento Base de Conhecimento Base de Dados Programas de Aplicação (Trns.

Wbps.Resultado final na Etapa de Desenvolvimento Transações (Trns) Procedimentos (Procs) Data Providers (DP) Web Panels (Wbps) Base de Conhecimento Base de Conhecimento Base de Dados Programas de Aplicação (Trns. Procs. 11 . contamos com uma aplicação pronta para executar.) Uma vez criada a base de dados e gerados os programas. etc.

dados. o GeneXus vai detalhar os mesmos num relatório de análise de impacto (IAR: Impact Analisis Report). ou não. etc. Wbps. que precisam ser realizados que refletem a nova realidade.As visões dos usuários mudam Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Base de Conhecimento Base de Conhecimento Base de Dados Nova Nova Base Base de de Dados Dados Programas de Aplicação (Trns. Mesmo assim. seja porque as visões dos usuários mudaram. Procs. ou acrescentar novos conhecimentos. Em caso de detectar mudanças para efetuar na base dados. é um relatório que explica todas as mudanças sobre tabelas. vai surgir repetidamente à necessidade de serem feitas modificações na base de conhecimento. As modificações realizadas na base de conhecimento serão analisadas pelo GeneXus para avaliar a necessidade de efetuar mudanças na base de dados (por exemplo: modificação/criação de tabelas/índices). ou porque devem ser feitas correções. 12 . DPs) Durante o ciclo de vida da aplicação. se informam os eventuais problemas que as mudanças em questões podem ocasionar como ter inconsistências ou redundâncias. índices. no relatório de análise de impacto.

ou renunciar a base de dados e deixar como estava. Wbps. 13 . Outras vezes isto não ocorre. Procs.Análise de Impacto Automático Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Análise de impacto Base de Conhecimento Base de Conhecimento Base de Dados Nova Nova Base Base de de Dados Dados Programas de Aplicação (Trns. O analista deve estudar o relatório de análise de impacto e resolver se deseja realizar efetivamente as mudanças na base de dados. e a base de dados sofre alguma modificação para representar a nova realidade. DPs) Algumas vezes a nova base de dados coincide com a anterior. ou fazer outras alterações.

DPs) Se o analista opta por aplicar as mudanças propostas. Utilizamos este termo para definir a ação de aplicar mudanças físicas sobre a base de dados. dizemos que optou por reorganizar a base de dados. e mediante sua execução nos brindará com uma nova versão da base de dados com as mudanças efetuadas. Procs.Geração de Programas de Reorganização da Base de Dados Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Programas de Reorganiz. 14 . Base de Conhecimento Base de Conhecimento Base de Dados Nova Nova Base Base de de Dados Dados Programas de Aplicação (Trns. GeneXus gera os programas que implementam as modificações sobre as estruturas físicas da base de dados. Wbps.

considerando as novas definições introduzidas. GeneXus estuda o impacto das alterações sobre os programas atuais. 15 .Análise automática do impacto das mudanças sobre os programas Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Base de Conhecimento Base de Conhecimento Análise de Impacto sobre os programas Nova Base de Dados Novos Programas de Aplicação (Trns. DPs) Visto que se quer reorganizar a base de dados ou não. Procs. Wbps.

obtendo assim uma nova versão da aplicação.Geração automática de novos programas Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Base de Conhecimento Base de Conhecimento Geração de programas Nova Base de Dados Novos Programas de Aplicação (Trns.) Por último. Procs. Wbps. GeneXus prossegue com a geração/regeração dos programas de aplicação necessários. etc. 16 .

com as mudanças aplicadas. 17 . com as mudanças na aplicação Novas Transações Novos Procedimentos Novos Data Providers Novos Web Panels Base de Conhecimento Base de Conhecimento Nova Base de Dados Novos Programas de Aplicação Assim novamente teremos uma aplicação pronta para executar.Nova realidade.

Environments • O Lugar onde se armazena a informação para gerar a aplicação em certa plataforma de execução se chama Environment. permite diferentes 18 . Environments: Implementation #1 C# & SQL Server C# Application SQL Implementation #2 GeneXus Project C# & MySQL C# Application MySQL Implementation #3 Java & MySQL Java Application MySQL Knowledge Base • O uso de vários Environments implementações da mesma aplicação.

servidor. etc).Environments • Quando se cria uma base de conhecimento (KB). No momento de criar a KB se começa a definir o ambiente de implementação (Environment) cujas definições serão depois completadas no momento de executar a aplicação (nome da base de dados. o item File / New Knowledge Base. Para criar uma base de conhecimento. mensagens. 19 . forma de conexão. GeneXus os utilizará para criar os programas associados a base de dados. se cria automaticamente um ‘Environment’. • Nome da Knowledge Base: em nosso caso será BillingSystem. As opções oferecidas são: C# Environment. • Diretório onde será criada. • Language: Idioma em que vai aparecer os botões. selecionar na barra do menu do GeneXus. • O ‘Environment’ por default: veja que são mostradas linguagens de programação. Java Environment e Ruby Environment. GeneXus pede ao usuário que selecione o Environment que vai trabalhar: • Com estes dados. etc. Em seguida vai aparecer um diálogo como o que segue: Deverá ser indicado.

Environments • Para ver o ‘Environment’ criado. selecionamos a janela de Preferences do Knowledge Base Navigator: Default Environment 20 .

21 . criamos vários ‘Environments’.Environments • Para ter implementações em diferentes plataformas.

22 .Environments • Vemos os ‘Environments’ criados: Environments: C# & SQL Server GeneXus Project Java & MySQL Knowledge Base O environment ativo é indicado em negro e tem o icone de “Play”.

Como explicado anteriormente.Metodologia Incremental Construir uma aplicação mediante aproximações sucessivas. este processo é realizado mediante aproximações sucessivas. 23 . conhecida como metodologia incremental. DEFINIÇÃO INICIAL A construção automática da base de dados e programas permite ao GeneXus aplicar esta metodologia de desenvolvimento.

No momento é suficiente saber que ao criar a base de conhecimento.) voltaremos no final. diferentes versões da aplicação. programas reais. serão uma versão da aplicação. etc. e pronto!. como realizar. os programas que estaremos executando. de teste. Uma vez que resolvermos que essa versão está pronta para ser colocada em produção.Metodologia Incremental Aplicar um desenvolvimento incremental. pode gerenciar • Versão para prototipação • Versão para colocar em produção Referente a versões (do que se trata. 24 . basta fazer outra ‘versão’ da aplicação.

animados por menus. até nos mínimos detalhes. Isto permite ajudar o usuário a ter uma idéia de como o sistema será construído. é que se acaba implementando uma solução relativamente insatisfatória. uma aplicação funcionalmente equivalente à desenhada.. etc. oferecida por diversos sistemas. regras do negócio. funcionalmente equivalente a aplicação de produção. imediatamente. 25 . relatórios. mas também suas fórmulas. Assim a aplicação pode ser totalmente provada antes de colocar em produção. e durante estes testes. O impacto destes problemas diminui muito se for possível testar cada especificação. Sabendo que a realidade não permanece estática. estruturas de dados. A conseqüência de manter as especificações. o usuário afinal pode trabalhar com os dados reais. porém no final. Isto somente é possível graças a construção automática que o GeneXus realiza do suporte computacional (base de dados e programas). para sua execução imediata. Uma situação bastante diferente seria colocar a disposição do usuário. sempre aparecem surpresas. é a possibilidade de mostrar ao usuário formatos de janelas. Isto é o que faz o GeneXus: um protótipo GeneXus é uma aplicação pronta. o custo em tempo e dinheiro em solucioná-los é muito grande. e trabalhar com seus dados reais. por isto não é razoável pensar que as especificações não vão mudar até que o sistema seja implementado. E muitos destes problemas somente são detectados nos testes finais do sistema. Uma primeira aproximação de resolução deste problema.Vantagens da Prototipação • • • • • Permite ver resultados no início Permite seguir os requerimentos do usuário Detecta os erros no início O usuário se compromete com o desenvolvimento Sistemas de melhor qualidade Toda comunicação é susceptível a erros: • O usuário esquece certos detalhes • O analista não toma nota de alguns elementos • O usuário se equivoca em algumas situações • O analista interpreta mal algumas explicações do usuário Como a implementação dos sistemas é habitualmente uma tarefa que consome bastante tempo. testando de uma forma natural não somente os formatos de telas. relatórios. etc. e saber qual é a repercussão de cada alteração sobre o resto do sistema. etc.

Os programas oriundos das transações têm o objetivo de permitir inserir. controlando estes programas e a integridade referencial dos dados. As transações permitem definir os objetos da realidade. se recomenda prestar atenção aos substantivos que o usuário menciona quando escreve a realidade. Para identificar quais são as transações que precisam ser criadas. 26 .Objeto Transação A análise de toda aplicação GeneXus começa com o desenho das transações. igual como os demais objetos GeneXus. provocam a geração de programas. Além de ter por objetivo a definição da realidade a conseqüente criação da base de dados normalizada. eliminar e modificar de forma interativa nas tabelas que tenham implicações. as transações.

definir validações sobre os dados.Transações Generalidades Definição Objeto a partir do qual GeneXus criará de forma automática a base de dados na 3ª forma normal • Descrevem as visões dos usuários. que serão vistos: Estrutura: Permite definir os atributos (campos) que compõem a transação e a reação entre elas. Category e Work With: Patterns (padrões) que podem ser aplicados a Transação com a finalidade de implementar de forma automática certa funcionalidade. etc. para ser utilizado como documentação do sistema. Alguns destes elementos também estão associados a outros tipos de objetos GeneXus. para ser consultado pelos usuários em tempo de execução da transação. • Contem toda a informação necessária referente os dados da aplicação e de como os usuários acessam o sistema para sua manipulação (inserir. Web Form: Cada transação contém um Form (tela) Web mediante o qual se realiza inserções. A partir deles. Ajuda: Permite a inclusão de texto de ajuda. modificar e eliminar). Variáveis: Permite a definição de variáveis que são locais a Transação. que se ativa em resposta a certas ações provocadas pelo usuário ou pelo sistema. o GeneXus conclui o desenho da base de dados: tabelas. etc. permitem definir valores por default para os atributos. Elementos que as compõem: Alguns elementos das transações. eliminações e alterações no ambiente Web. Documentação: Permite a inclusão de texto técnico. Propriedades: Permitem definir certos detalhes referentes ao comportamento da transação. índices. 27 . Eventos: As transações suportam a programação orientada a eventos. Regras: As regras permitem definir o comportamento particular das transações. chaves. Este tipo de programação permite definir código ocioso. Por exemplo.

esse asterisco em GeneXus aparece representado por um ícone de chave e o usuário pode configurá-lo mediante um menu contextual que oferece esta possibilidade. se numa aplicação é necessário registrar informação de fornecedores. um endereço SupplierAddress e um telefone SupplierPhone. SupplierName. _____________________________________________________________________________ 1 O asterisco corresponde a uma notação teórica que utilizamos para indicar que o atributo é identificador.Transações Estrutura Exemplo: Precisa registrar informação de fornecedores. descrição e alguns outros detalhes mais que veremos. com estrutura: { SupplierId* SupplierName SupplierAddress SupplierPhone } Identificador de fornecedor Nome de fornecedor Endereço de fornecedor Telefone de fornecedor A estrutura de uma transação permite definir que atributos integram a mesma e como estão relacionados. Então. Para cada atributo definido na estrutura. Por exemplo. 28 . Definir a transação “Supplier”. deveremos indicar coisas como seu tipo de dados. terá que ser definido uma transação. criamos uma transação de nome “Supplier” cuja estrutura é composta dos atributos SupplierId*. SupplierAddress e SupplierPhone. Como veremos. Isto significa que cada fornecedor é identificado por um código SupplierId (o qual fica determinado pelo asterisco após o atributo¹). a qual podemos dar o nome “Supplier” e sua estrutura pode ser a seguinte: {SupplierId* SupplierName SupplierAddress SupplierPhone } Esta lista de nomes (um dos quais está sucedido do símbolo asterisco) corresponde aos atributos dos fornecedores que interessam ser mantidos. terá um nome SupplierName.

assim como não definir nenhum. um ícone de chave representa o asterisco que usamos como notação teórica.Transações Estrutura Estrutura em GeneXus: Atributos Chave Na página anterior foi explicado que o asterisco após o atributo SupplierId indica que o mesmo é o identificador na transação. deve-se optar por criar um atributo artificial (não existente na realidade). Em definitivo se trata do conceito de chave primária. e que seu valor seja atribuído internamente. Como pode ser observado no editor de transações GeneXus. isto é. Em outras palavras seriam os atributos que tem maior carga semântica na transação. Por default o primeiro atributo na estrutura da transação que seja do tipo de dados character. se define como “atributo descriptor”. É possível definir outro atributo como descriptor utilizando o menu pop-up correspondente. um atributo ou conjunto de atributos que definam a unicidade da informação. No exemplo não vão existir dois fornecedores com o mesmo valor de SupplierId. Nos casos em que não se pode determinar um identificador. e para fazer a escolha dos atributos que a compõem. por exemplo. 29 . Toda transação deve ter pelo menos um identificador. na forma correlativa. devemos levar em consideração os requisitos da realidade do objeto. Atributo “descriptor” O ícone com uma lupa representa o atributo que melhor descreve a transação.

elimina ou se altere conjuntamente na base de dados. para cada instancia do nível anterior. deve ser indicado quais atributos atuam como identificador. para representar que os atributos contidos formam parte de um nível aninhado. não necessitando de um jogo de chaves.Transações Estrutura Exemplo: Precisa registrar informação referente a fatura de venda. O identificador de cada nível pode ser composto somente de um atributo. como é o caso das transações que vimos até agora. um cabeçalho da fatura e seus vários produtos. A diferença da transação “Invoice” que contém dois níveis. Chamamos de transação plana a uma transação de um nível só. Para cada nível da transação. e que tem uma representação visual em GeneXus distinta. mas indica o mesmo. Assim. Invoice { InvoiceId* InvoiceDate CustomerId CustomerName Identificador de fatura Data de fatura Identificador de cliente Nome de cliente Detail { ProductId* Identificador de produto ProductDescription Descrição de produto ProductPrice Preço de produto InvoiceDetailQuantity Quantidade de produto levada da linha InvoiceDetailAmount Valor da linha de fatura } InvoiceAmount Valor total da fatura } Níveis de uma transação A transação “Invoice” consta de dois níveis: o primeiro nível fica implícito. ou pode ser composto por vários atributos. podemos dizer que a transação “Supplier” é a transação plana. Cada nível de uma transação define um grupo de atributos que devem operar em conjunto. É comum falarmos de “cabeçalho” para o primeiro nível e de “linhas” para o segundo. não é repetido o valor do atributo ProductId em distintas linhas. assim como aninhados. Uma transação pode conter vários níveis paralelos. ____________________________________________________________________________ 1 O asterisco é uma notação teórica representando que o atributo que o antecede é identificador na transação. ou seja. 30 . se insere. O fato de definir um segundo nível significa que existem várias instâncias do mesmo. No exemplo. Este último significa que para um número de fatura dado. o jogo de chaves também é utilizado como notação teórica. e o segundo nível corresponde ao conjunto de atributos que ficam definidos entre chaves ¹. Na transação “Invoice” o atributo InvoiceId é o identificador do primeiro nível. e o atributo ProductId + o atributo dos níveis superiores é o identificador do segundo nível.

será utilizada para trabalhar com business components. A cada nível de uma transação se deve atribuir um nome. poderíamos definir dois tipos de estrutura. mas entre eles.Transações Estrutura Estrutura em GeneXus Em GeneXus fica visualmente claro o nível correspondente as linhas da fatura. Níveis paralelos e aninhados Uma transação pode ter vários níveis aninhados. 31 . são paralelos. dependendo do que se quer representar: Invoice { InvoiceId* InvoiceDate CustomerId CustomerName InvoiceAmount Detail {ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount} Payment {InvoicePaymentDate* InvoicePaymentAmount} } Invoice { InvoiceId* InvoiceDate CustomerId CustomerName InvoiceAmount Detail {ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount Payment {InvoicePaymentDate* InvoicePaymentAmount}} } Na estrutura da esquerda é definido uma fatura que tem muitos produtos e muitos pagamentos. que recebe como nome o da transação). É fácil compreender que o segundo e o terceiro nível da transação da esquerda são paralelos. no caso hipotético que uma fatura pode ter vários pagamentos. Por exemplo. Na estrutura da direita são registrados os pagamentos por produto comprado. Na estrutura da direita. o tipo que se define para um nível de uma transação. mas não tem relação direta entre os produtos e os pagamentos (a não ser pelo fato de pertencerem à mesma fatura). tipo1 e descrição (exceto ao primeiro nível. ________________________________________________________________________________________ 1 Como veremos depois. Ambos estão aninhados ao primeiro nível. são todos os níveis aninhados. assim como níveis paralelos. conceito relacionada as transações.

SupplierPhone} Dadas estas dependências funcionais. e que estará conforme nem mais nem menos que pelos quatro atributos anteriores. Para poder realizar a normalização da base de dados ser realizada numa 3ª forma normal. modificar ou eliminar pela transação. para distinguir o nome de uma tabela do nome de uma transação escreveremos o nome da tabela em maiúsculo.Transações Definição do modelo de dados: estruturas das transações Transação Supplier { SupplierId* SupplierName SupplierAddress SupplierPhone } Transação Invoice { InvoiceId* InvoiceDate CustomerId CustomerName Detail { ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount } InvoiceAmount } Tabela INVOICE InvoiceId* InvoiceDate CustomerId CustomerName InvoiceAmount Tabela INVOICEDETAIL InvoiceId* ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount Tabela SUPPLIER SupplierId* SupplierName SupplierAddress SupplierPhone GeneXus utiliza a estrutura das transações para capturar o conhecimento necessário para definir automaticamente qual é o modelo de dados que será criado. GeneXus deve extrair as dependências funcionais existentes entre os atributos definidos na base de conhecimento. temos definido na transação “Supplier” e de sua estrutura GeneXus extraímos as seguintes dependências funcionais: SupplierId {SupplierName. assim estarão armazenando. 32 . GeneXus determina que deve criar uma tabela que terá por default o mesmo da transação (SUPPLIER)1. modificando ou eliminando fisicamente na tabela associada. sendo SupplierId a chave primária da mesma: SUPPLIER SupplierId SupplierName SupplierAddress SupplierPhone Diremos que a transação “Supplier” tem a tabela associada SUPPLIER quando inserir. SupplierAddress. Na base de conhecimento de nosso exemplo. _____________________________________________________________________ 1 Na documentação.

InvoiceAmount} {InvoiceId. InvoiceDetailAmount} Observe que a chave primária da tabela INVOICEDETAIL é a concatenação do identificador do primeiro nível. correspondente ao primeiro nível da transação: Chave primária: InvoiceId INVOICE InvoiceId CustomerId CustomerName InvoiceDate InvoiceAmount Tabela INVOICEDETAIL correspondente ao segundo nível da transação: INVOICEDETAIL InvoiceId ProductId ProductDescription InvoiceDetailAmount ProductPrice InvoiceDetailQuantity Chave primária: {InvoiceId. 33 . com o identificador desse nível. GeneXus determina que deve criar duas tabelas: Tabela INVOICE. A regra é geral: a chave primária da tabela correspondente a um nível n de uma transação se obtêm em concatenar os identificadores dos n-1 níveis anteriores aninhados. com o identificador do segundo nível. ProductId. GeneXus atribuiu um nome pré-determinado às tabelas que cria. ProductPrice. A tabela associada ao primeiro nível de uma transação atribui o mesmo nome que o da transação. Os nomes das tabelas podem ser modificados pelo analista GeneXus quando o desejar. CustomerName. ProductId} Chave estrangeira: InvoiceId já que as dependências funcionais são: InvoiceId {CustomerId. ProductId} {ProductDescription. Por isso é que a tabela associada ao segundo nível da transação “Invoice” recebe o nome de INVOICEDETAIL. e as tabelas dos níveis subordinados são atribuídas a concatenação dos nomes dos níveis. InvoiceDetailQuantity. e o segundo nível é DETAIL. InvoiceId. sendo que o nome do primeiro nível é o da transação INVOICE.A partir da estrutura da transação “Invoice”. InvoiceDate.

Isto é. Dependências funcionais Com estas novas transações definidas. os clientes e os produtos são dois objetos de realidades independentes das faturas. damos conta que existem informações de clientes e produtos que é interessante manter independente das faturas. aparecem novas dependências funcionais: CustomerId {CustomerName.Transações Estrutura Ao definir as novas transações: Customer { CustomerId* CustomerName CustomerAddress CustomerGender } Sexo do cliente Product { ProductId* ProductDescription ProductPrice ProductStock } Depois de ter modelado a transação “Invoice”. CustomerAddress. CustomerGender. ProductStock} Que conduzem diretamente a criação de duas novas tabelas: CUSTOMER CustomerId CustomerName CustomerAddress CustomerGender Chave primária: CustomerId E: PRODUCT ProductId ProductDescription ProductPrice ProductStock Chave primária: ProductId 34 . para isso é necessário criar duas novas transações "Customer" e "Product" detalhadas acima. ProductPrice. CustomerStatus} ProductId {ProductDescription.

etc. Do contrário. pode pedir ao docente. 35 . Se representarmos sobre as tabelas CUSTOMER e INVOICE as dependências funcionais encontradas para os seus atributos: Podemos ver claramente que INVOICE viola a 3ª forma normal (existe uma dependência funcional transitiva): InvoiceId CustomerId CustomerId CustomerName InvoiceId CustomerName por tanto GeneXus normaliza.Transações Normalização: alterações nas tabelas Tabela INVOICE InvoiceId* InvoiceDate CustomerId CustomerName InvoiceAmount Tabela CUSTOMER CustomerId* CustomerName CustomerAddress CustomerGender Tabela SUPPLIER SupplierId* SupplierName SupplierAddress SupplierPhone Tabela INVOICEDETAIL InvoiceId* ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount Tabela PRODUCT ProductId* ProductDescription ProductPrice ProductStock O conjunto total de dependências funcionais existentes requer algumas modificações nas tabelas INVOICE e INVOICEDETAIL desenhadas previamente para que o desenho da base de dados permaneça na 3ª forma normal1. _______________________________________________________________________________ 1 Para mais informação sobre as formas normais (3ª forma normal. tirando o atributo CustomerName da tabela INVOICE: Agora CustomerName somente estará na tabela CUSTOMER. que está incluído no capítulo “Anexos” do curso GeneXus não presencial.) recomendamos a leitura do documento “Fundamentos de bases de dados relacionais”.

Agora veremos as dependências funcionais encontradas nas tabelas PRODUCT e INVOICEDETAIL: podemos perceber claramente que a tabela INVOICEDETAIL está violando a 3ª forma normal (existem atributos que dependem de forma parcial da chave primária): ProductId {InvoiceId. tirando os atributos ProductDescription e ProductPrice da tabela INVOICEDETAIL: ProductDescription e ProductPrice somente ficarão na tabela PRODUCT. ProductId} ProductDescription ProductDescription ProductId {InvoiceId. ProductId} ProductPrice ProductPrice Portanto GeneXus normaliza. 36 .

analisa que: o atributo tem o mesmo nome em ambas transações. com isso.. o qual significa que é chave primária na tabela física CUSTOMER. entende que trata-se do mesmo conceito.. assim possuem o mesmo conceito. de modo que. na verdade é um atributo secundário já que não é identificador em nenhuma transação do modelo. o GeneXus entende que trata-se de um atributo secundário.. As dependências funcionais indicam que o CustomerName o determina CustomerId: InvoiceId CustomerId CustomerId CustomerName assim que o GeneXus incluirá a CustomerName na tabela física CUSTOMER (e não na tabela física INVOICE). mas a diferença de CustomerId. } Conceitos iguais devem ter o mesmo nome e conceitos diferentes devem ter nomes diferentes. não está marcado como identificador em nenhuma transação do modelo. CustomerId é um atributo primário.. } incorreto VendorInvoice { VendorInvoiceId* Date SupplierId* SupplierName . quando encontra atributos com o mesmo nome em diferentes transações. CustomerName. e mediante este conhecimento é que pode normalizar.. } Customer { CustomerId* CustomerName } Invoice { InvoiceId* InvoiceCustomerId . também se encontra tanto na transação "Customer" como na transação “Invoice”..Transações Relações: estabelecidas pelos nomes de atributos • Conceitos iguais devem ter o mesmo nome Invoice { InvoiceId* CustomerId CustomerName .. quando o GeneXus encontra o atributo de nome CustomerId tanto na transação "Customer" como na transação "Invoice". O atributo CustomerName. No exemplo que estamos utilizando. } Customer { CustomerId* CustomerName } • Conceitos diferentes NÃO devem ter o mesmo nome Invoice { InvoiceId* Date CustomerId CustomerName . por sua parte. No exemplo que estamos vendo. O GeneXus estabelece as relações através dos nomes dos atributos. Atributos primários e secundários Um atributo se qualifica como primário quando o mesmo é identificador em alguma transação do modelo. Na transação "Customer" CustomerId está marcado como identificador.. então na tabela física INVOICE será chave estrangeira. já que é identificador na transação "Customer". 37 .

serão incluídos nas transações "Customer" e "Product" respectivamente. porque notamos a necessidade de criar estes objetos. os atributos ProductDescription e ProductPrice também são inferidos na transação “Invoice”. já que seu valor não está armazenado em nenhuma das tabelas associadas a mesma. como temos explicado. por exemplo. se obtêm . Nas estruturas das transações podem ser incluídos atributos que não estarão nas tabelas físicas associadas às mesmas. mas sim que seus valores se inferem na tabela PRODUCT. 38 Product { ProductId* ProductDescription ProductPrice ProductStock } . e foram incluídos nas transações "Customer" e "Product" respectivamente.da tabela CUSTOMER. passarão a serem atributos primários. Ditos atributos. o GeneXus analisa o conjunto total de dependências funcionais existentes na base de conhecimento. ProductDescription e ProductPrice continuam na estrutura da transação "Invoice". apresentamos 3 estruturas das transações em questão. e ao serem marcados como identificadores das mesmas. em tempo de execução quando o usuário ingressa através de algum dos forms (GUI-Windows e/ou Web) um valor de CustomerId (atributo que armazenará na tabela INVOICE sendo chave estrangeira). para poder visualizálas juntas: Invoice { InvoiceId* InvoiceDate CustomerId CustomerName Detail { ProductId* ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount } InvoiceAmount } Customer { CustomerId* CustomerName CustomerAddress CustomerGender } Provavelmente você está se perguntando qual a razão dos atributos secundários CustomerName. para serem mostrados na tela. e assim poder visualizar os valores destes atributos em tempo de execução. Posteriormente. Os atributos CustomerId e ProductId. por sua vez. Estes são atributos secundários. nos forms (GUI-Windows e/ou Web) associados a transação “Invoice”. por exemplo.ou modifica. deixando-as na 3ª forma normal. segundo o caso . O atributo CustomerName. A explicação é a seguinte: as estruturas das transações. e os atributos ProductDescription e ProductPrice na transação "Product". Todos os atributos antes mencionados estão em mais de uma transação: partindo do princípio que continuam na transação “Invoice” tal como foi definido no princípio.Atributos Armazenados e Inferidos Ao definir as transações "Customer" e "Product". ProductDescription e ProductPrice na estrutura da transação “Invoice”? Foram deixados para poder incluí-los em algum dos elementos do objeto da transação. se agregou na transação "Customer". com que finalidade temos deixado os atributos secundários CustomerName. nem na tabela INVOICEDETAIL. já que não se encontram armazenados nas tabelas associadas à mesma.as tabelas físicas. mas sim que se infere – isto é. não ficam armazenados na tabela INVOICE. incluímos nelas certos atributos que não eliminados da transação “Invoice”. não são equivalentes às estruturas de tabelas físicas. Dizemos que o atributo CustomerName é um atributo inferido na transação "Invoice". Analogamente. a continuação mostrará CustomerName correspondente. Agora. dado o valor do atributo CustomerId. já que na hora de reorganizar a base de dados. e cria .

• Facilitam a tarefa de dar nome. • Facilitam a tarefa de integração de bases de conhecimento. • Facilitam a leitura do código gerado.Transações Estrutura É conveniente usar padrões para os nomes dos atributos. 39 .

o objeto evento (ex: VendorInvoice. _____________________________________________________________________________ 1 Para países que utilizem línguas nas quais os adjetivos são colocados depois do substantivo. Exemplo: A fatura tem os seguintes componentes. Stock (estoque). 40 . Name (nome). por isso a categoria (ou substantivo) vai no final. InvoiceLine (linhas da fatura). que falaremos mais adiante. Fatura de Venda) que intervêm em uma dada aplicação. Sugere que não ultrapasse os 10 caracteres.Transações Estrutura Nome de atributos: Nomenclatura GIK Componente de Entidade + Categoria [+ Qualificador + Complemento] Entity Component Cliente Cliente Cliente Cliente Fatura Fatura FaturaDetalhe FaturaCompra Category Id Nome Data Data Id Data Quantidade Id Vencimento Inicial Final Qualifier …e em inglês: Entity Component Customer Customer Customer Customer Invoice Invoice InvoiceDetail VendorInvoice Due Start End Qualifier Category Id Name Date Date Id Date Amount id A ARTech definiu um padrão para a nomenclatura de atributos: o GeneXus Incremental Knowledge Base (GIK) que é utilizado pela comunidade de usuários GeneXus. Date (data). representado por uma transação GeneXus². Description (descrição). assinalados entre parênteses retos): Componente de Entidade + Categoria [+ Qualificador + Complemento] 1 Posteriormente descrevemos em que consiste cada componente: Componente de Entidade (ou Objeto): uma Entidade é um ator (ex: Customer). Em inglês é ao contrário. Invoice (cabeçalho). o nome de um atributo se forma com 4 componentes (alguns opcionais. Se sugere um tamanho de 10 caracteres para representar o componente da Entidade. Nesta nomenclatura. Categoria: É a Categoria semântica do atributo que define o rol que o mesmo assume dentro do objeto e dentro do ambiente da aplicação. Um Componente de Entidade representa qualquer nível subordinado ou paralelo que defina a entidade. Price (preço). Exemplos: Id (identificador). Code (código). 2 Ou um conjunto de Transações paralelas e/ou subordinadas.

entorno de 10 caracteres. Exemplos: Start (inicial).Qualificador: É qualquer adjetivo ou advérbio. No slide se mostram alguns exemplos de nomes de atributos. 41 . Due (vencimento) que agregue Complemento: Texto livre até completar a quantidade de caracteres significativos (30) para o nome. ainda se sugere utilizar 10 e que o nome completo não seja superior a 30. Nota 2: Para cada componente se podem utilizar a quantidade de caracteres desejada. Em geral refere ao texto que qualifica a categoria: Data de Vencimento. Nota 1: As letras maiúsculas permitem estabelecer fronteiras entre os componentes que formam os nomes dos atributos. End (final). diferenciação conceitual ao nome do atributo para que o torne único.

É mostrado um diálogo onde se deve escolher o tipo de objeto que se deseja criar (neste caso o tipo de objeto: transação).Demo Uma vez criada a base de conhecimento: criação das primeiras transações Uma vez criada a base de conhecimento. Object. dar um nome ao objeto que se está criando (por exemplo: “Customer”). e a pasta na qual guardar o objeto: Uma vez criada a transação. 42 . se realiza pressionando Ctrl+N. Os objetos criados ficarão ou na pasta Objects que se pode ver no Folder View da janela KB Navigator. Se desejar que o objeto ao ser criado fique guardado em outra pasta. Também poderá ser indicado a pasta no quadro de criação de um objeto como se vê na imagem. a mesma ficará aberta para que se defina sua estrutura. uma descrição longa. No menu escolher New. se deve posicionar em dita pasta e depois fazer click com o botão direito do mouse. a mesma ficará aberta para começar a criar as transações. A criação de objetos.

Cada atributo contém propriedades. Uma vez definidos os atributos na estrutura da transação. GeneXus conta com menus pop-up². etc. Com a tecla Enter pode-se passar a seguinte linha. nulabilidade. e o mesmo é habilitado e pode ser editado. simplesmente deve-se digitar no primeiro campo de uma linha (ou ramo) da estrutura. e no caso que o mesmo venha a ser uma fórmula (conceito que veremos em breve). que são menus que se abrem quando o usuário está posicionado em determinado contexto e fazendo click com botão direito do mouse. descrição. assim. permite autonumerar atributos chave primária. deve-se selecionar o item Properties do menu contextual. Caso necessite modificar o nome de um atributo. deve-se selecionálo e clicar CTRL +D. Para definir o início de outro nível na transação. deve-se digitar CTRL+L. seu tipo de dados. Algumas delas (as fundamentais e obrigatórias) são as que se oferecem diretamente na estrutura para seu ingresso “inline”. Para indicar que um atributo de um dos níveis da transação será o atributo “descriptor”. ao clicar com o botão direito do mouse sobre um atributo da estrutura.Transações Definição de atributos F4 Para definir um atributo. como definir o nome de seu tipo de dado¹ e uma descrição para o nível. Mediante a tecla de tabulação pode-se passar aos seguintes campos para indicar o tipo de dados do atributo. 43 . Para indicar que um ou mais atributos são identificadores na transação. somente restará guardar/salvar as mudanças. o nome do atributo que se deseja criar. Por exemplo. que oferece varias utilidades. passá-lo a um seguinte nível de animação. Também chamados “contextuais” visto que variam segundo o contexto. aparecerão com um símbolo de chaves. assim como sua descrição. _______________________________________________________________________________________ 1 2 Veremos sua utilidade enquanto estudarmos os “business components”. Após as alterações as mudanças precisam ser salvas novamente. como por exemplo indicar que o atributo é chave (opção “Toggle key”). Na figura alteramos a propriedade Autonumber que como veremos oportunamente. deve-se selecioná-los e pressionar CTRL+K. para definir outro atributo. bastará dar um duplo clique sobre o campo desejado. ou pressionando a tecla F4. tira-lo da estrutura. Para acessar o diálogo que permite configurar todas as propriedades de um atributo. ou fórmula. como calculá-la. abre-se um menu pop-up sobre o atributo selecionado. e automaticamente se produz uma endentação e o usuário deverá dar um nome a esse nível.

com o GXQuery.significa que os valores válidos são entre 1 e 20. o ponto decimal é o sinal. mas em resumo. Por exemplo: pode-se definir um domínio de nome Price e tipo de dados Numeric(10. É recomendável a leitura de todas as outras propriedades e não somente estas. por exemplo: no primeiro nível dos forms das transações (veremos em breve os forms). Dependendo do tipo de dados do atributo. já que será através desta descrição que o usuário final poderá selecionar atributos para definir suas próprias consultas na base de dados. haverá certas propriedades. Data Type e Length) tomando os valores do domínio. e as propriedades correspondentes ao tipo de dados do atributo estarão habilitadas para serem ingressadas. Relacionadas a esta propriedade. determinadas propriedades abaixo desta classe são disponibilizadas. 3 o 4. O atributo deve ser bem identificável com essa descrição.significa que os valores válidos são 'S' ou 'N'. • 1234 .2) e depois associar este domínio para todos os atributos que armazenam preços.Name: É o nome do atributo. Data Type: Permite indicar o tipo de dados do atributo. para indicar se tem sinal ou não. indica que trata um inteiro. As 2 primeiras por default tem o mesmo valor especificado no Description. então. e 30 ou maior.2). Utilizado para identificá-lo. dependendo do valor que se escolhe para determinada propriedade. ________________________________________________________________________________________ 1 O atributo também pode estar num objeto objeto Web Panel. isto é. certas propriedades do atributo são desabilitadas (como por exemplo. estão às propriedades Title. (no caso de uma transação somente se trata de um atributo inferido. para configurar. • 'S' 'N' . Column Title: A descrição aqui inserida é por default como o título do atributo. Nesse caso. Observe que por default se pega da propriedade Description. Ao atribuir um domínio a um atributo. o nome da coluna do grid da transação pega desta propriedade. 44 . dever ser considerado que o tamanho inclui as posições decimais. 2. tem que modificar somente a definição do domínio e automaticamente todos os atributos baseados nesse domínio herdam essa mudança. podendo ser modificado. de Signed: Se na propriedade Data Type se indica que o atributo é numérico. cada vez que for incluído na coluna de um grid. quando trata do tipo de dados Date). Description: A “Descrição” ou mais propriamente “Nome extenso” é uma definição ampliada do atributo. sempre será oferecido por default para o nome da mesma o de sua propriedade Column Title. Tem a vantagem que se depois desejar modificálo por exemplo para Numeric(12. não se deve atribuir dois atributos na base de conhecimento com a mesma descrição. e não é inferido (exemplo InvoiceDetailQuantity em Invoice). Column Title e Contextual Title. Decimals: Se a propriedade Data Type indica que o atributo é numérico. o objetivo dos domínios é realizar definições de dados genéricos. mas que não será abordado neste curso). Title: A descrição aqui inserida é colocada por default ao lado do atributo. O GeneXus fornece um número maior de propriedades dos atributos que as já mencionadas. e principalmente deve ser entendível pelo usuário final. Contextual Title: Quando o atributo pertence ao segundo nível de uma transação. o que indica que não serão representados valores negativos. são disponibilizadas certas propriedades relacionadas ou outras. pois assume o contexto. onde é escolhido um dos tipos de dados suportados pelo GeneXus. acessando o Help do GeneXus. Em caso do atributo não pertencer a um domínio. com independência do contexto. Length: Permite indicar o tamanho do atributo. O valor por default é “False”. Deve ser um identificador global do atributo. Se na propriedade Data Type indica que o atributo é numérico.significa que os valores válidos são 1. ou outras. o programador deixará o valor [none] nesta propriedade. esta propriedade é oferecida. cada vez que se utilize em saídas “planas” como. Dependendo do tipo de dados selecionados. Por exemplo: • 1:20 30: . 2 Os domínios serão abordados mais adiante no curso. Esta propriedade estará desabilitada quando o tipo de dados escolhido requer estabelecer um tamanho (por exemplo. executando “relatórios dinâmicos” (tema bastante simples. como por exemplo o atributo ProductDescription na transação Invoice)1. Type Definition Based on: Permite associar um domínio ao atributo. para especificar a quantidade de decimais. O valor 0 neste campo. Picture: Permite indicar o formato de edição para a entrada e saída do atributo. de aparecer como coluna. esta propriedade é oferecida. Validation Value Range: Permite indicar uma faixa de valores válidos para o atributo. mas tirando o nome da transação.

entre outras. cada vez que seja incluso em um form. apresentará automaticamente com o tipo de controle que tenha associado. No grupo Control Info do diálogo de edição das propriedades de um atributo. Logo. se apresente automaticamente com as cores que ele tenha associado (ver grupo Appearance). podendo ser alterado pelo programador para qualquer um dos outros tipos. é onde o programador pode mudar o tipo de controle associado ao atributo. Em geral GeneXus escolhe o tipo de controle para um atributo dependendo de seu tipo de dados. de modo que cada vez que se agregue o atributo em um form.Edit . dependendo da quantidade de valores de domínio. 45 .Dynamic Combo Box .Radio Button . Quando um atributo é definido com um tipo de dados básico. como veremos. e dependendo do tipo de controle escolhido. quando estudarmos “Descrições ao invés de códigos”. e incluso que sugira os valores possíveis ao usuário. uma informação distinta pode ser solicitada. poderá especificar que “disfarce” seus valores. serve para especificar o tipo de controle por default que será usado pelo atributo. como veremos depois. Se é um domínio enumerado.Dynamic List Box A associação de certo tipo de controle de um atributo. o tipo de controle associado a ele é o Edit.List Box .Control Info Um atributo pode associar um tipo de controle. Também se pode escolher a cor da fonte da letra que se deseja associar por default ao atributo. Nota No caso de associar ao atributo o tipo Edit. cada vez que um atributo é agregado em um form. escolherá Radio Button ou Combo Box.Combo Box . a medida que este vá digitando (propriedade Suggest). assim como a cor de fundo. Os possíveis tipos de controles: .Check Box . mostrando os de outro atributo (propriedade InputType).

na base de dados. etc. exceto na forma que é armazenada no BD. (memo). • Boolean: permite que um atributo ou variável assuma os valores lógicos: True. . A escolha de apresentar o ano com 2 dígitos ou 4. vídeos. Para este tipo de dados. False. é de tipo Character e sabemos que nunca um nome terá mais de 20 caracteres. planilhas.Permite armazenar uma combinação de data e hora. podemos fixar o tamanho: 20. imagens. Date: Permite armazenar uma data. Boolean VarChar .Permite armazenar qualquer tipo de informação: texto.Permite armazenar textos longos. O objeto “language” existe para poder ter uma mesma aplicação traduzida em qualquer linguagem. Character. Quando se seleciona este tipo de dados se deve indicar a quantidade total de dígitos do número.Equivalente a Character. Long Varchar . estamos especificando que representará números com até 7 dígitos na parte inteira e 2 decimais (7 dígitos na parte inteira + ponto + 2 dígitos para os decimais = 10 dígitos). será deste tipo de dados. Blob . etc.Transações Atributos: Tipos de Dados Numeric. e sem sinal.Propriedades Maximum Length e Avarage Length associadas. 46 . se configura em forma genérica para todo o modelo dentro de um tipo especial de objeto. mês-dia-ano). o objeto Language correspondente a linguagem que vai ser gerado o modelo. deve ser indicado o tamanho. Exemplo: O atributo InvoiceDate que utilizamos para armazenar a data de uma fatura. se configura com a propriedade Picture de cada atributo. comentários. Exemplo: O atributo CustomerName que utilizamos para armazenar o nome de um cliente.. e se permite sinal ou não. a quantidade de posições decimais. Numeric: Permite armazenar dados numéricos. com decimais 2. Character: Permite armazenar qualquer tipo de texto (caracteres e dígitos). O formato a utilizar para as data (dia-mês-ano. DateTime . Exemplo: Se definimos que o tipo de dados do atributo InvoiceAmount é numérico de tamanho 10. Date.

tendo como parâmetro o nome do atributo. Referente a hora podemos escolher entre: mudar somente 2 dígitos para a hora (não administrando minutos nem segundos). aproveitando assim os diferentes mecanismos de integridade e controle fornecido pelos DBMSs. e o resto em um área de overflow. já que primeiro consulta a quantidade de linhas que tem certo atributo Long Varchar. e a quantidade de caracteres que deseja considerar por linha. por exemplo). Podem ser aplicadas todas as funções e operadores existentes para o tipo de dados Character. se criará o atributo do tipo Character. tendo como parâmetro o nome do atributo. Sua função. Geralmente estas 2 funções são usadas combinadas. A propriedade Picture deste tipo de dados. mudar 2 dígitos para a hora e 2 dígitos para os minutos (não administrando segundos). e o que desejamos mostrar sobre a hora. mudar 2 dígitos para a hora. A primeira é para indicar o tamanho máximo de caracteres que poderão armazenar. caso não seja especificado a forma de aceitar ou mostrar seu conteúdo. normalmente utilizado para armazenar textos grandes. só a hora. exceto nos casos em que o dado seja de tamanho maior que 25. isto é. extrai uma linha do atributo Long Varchar (para depois imprimi-la. indicando a quantidade desejada de caracteres por linha. Nota: Em caso de não alterar a data. GXMLines retorna a quantidade de linhas que tem um atributo Long Varchar. Exemplo: &cantlin = GXMLines( AtribMemo. Os valores antes mencionados não afetam a forma de armazenar o tipo de dados. comentários. se o dado tem tamanho menor ou igual que 25. quando ficam armazenados os primeiros 25 caracteres no campo. os valores não aceitados (minutos e/ou segundos) serão armazenados com valor zero. o valor da data que ficará no campo será o mínimo suportado pelo DBMS. a capacidade restante de armazenamento do atributo (35 caracteres). permite escolher o que desejamos mostrar sobre a data. Se o DBMS não suporta este tipo de dados. 40 ). aperfeiçoa o armazenamento da seguinte forma: se definir Avarage Length (por exemplo: 25). O tipo de dados Varchar é equivalente ao tipo Character em todos os sentidos.• VarChar: Permite armazenar texto de tamanho variável. e desta forma eles são impressos. O tipo de dados Blob permite armazenar esta diversidade de informação na própria base de dados. e depois prossegue extraindo o conteúdo das linhas. 1. •DateTime: Permite armazenar uma combinação de data e hora. por exemplo. enquanto que a segunda é para indicar o tamanho médio de caracteres que se vai armazenar pelo geral. exceto na forma em que armazena os caracteres na base de dados. O tipo de dados Varchar. Long Varchar: Permite definir um atributo memo. mudá-la e apresentar o ano com 2 dígitos. se inserimos um dado que ocupa 25 caracteres. o número da linha desejado. mudá-la e apresentar o ano com 4 dígitos. utilizando um loop até chegar à última linha. e será reconhecido pelo GeneXus como data vazia ou nula. etc. e Maximum Length (por exemplo: 60). Quando se seleciona o tipo de dados Varchar no diálogo de definição do atributo se acrescentam as 2 seguintes propriedades: Maximum Length e Avarage Length. 40 ). Referente a data podemos escolher entre: não mudá-la. O GXGetMLi por sua vez. fica armazenado no campo (se completa brancos). Existem duas funções para manipular este tipo de dados: GXMLines e GXGetMLi. No que se diz respeito à hora. será necessário realizar um acesso adicional tanto para a leitura como para a gravação do dado. então. em contraposição ao Character. Ao selecionar este tipo de dados deve-se indicar um tamanho máximo de caracteres. é otimizar o armazenamento na base de dados. para os casos que se utilize a área de overflow. Para aprofundar o conhecimento nesse tipo de dados entrar no Help GeneXus. 2 dígitos para os minutos e 2 dígitos para os segundos. Exemplo: &txt = GXGetMLi( AtribMemo. e a quantidade de caracteres que se deseja considerar por linha. se completa com brancos. Em contrapartida a vantagem de otimização do armazenamento. Exemplo: Quando se define um atributo do tipo Character e tamanho 60. Este tipo de dados somente pode ser utilizado quando se tem um DBMS. Blob: As aplicações requerem cada vez mais manter e trabalhar com este tipo de informação. 47 .

são locais. Editor similar ao da estrutura das transações: É possível definir variáveis do tipo coleção (qualquer tipo de dados). Este diálogo solicita o nome da variável. isto é. O valor que oferece por default esta propriedade é escalar. o domínio. tipo de dados e tamanho. como por exemplo a variável Today que contem a data do sistema) para o objeto. deve selecionar o seletor Variáveis. sua descrição. As variáveis são visíveis somente dentro do objeto. Para definir variáveis em determinado objeto.Transações Definição de variáveis Em todo objeto GeneXus é possível definir variáveis. como se mostra na figura. 48 . e permite definir variáveis novas através de um editor similar ao das transações. No quadro de diálogo que se mostra para selecionar New Variável. A propriedade Dimensions permite indicar se a variável será escalar ou se tratará de um vetor (1 dimensão) o matriz (2 dimensões). Também se pode ir a opção Insert do menubar e escolher Variables. de forma análoga quando se define um atributo. Este seletor mostra variáveis definidas por default (Standard variáveis.

e declaramos: For &OneNumber in &myNumbers ---------Endfor 49 . Para isso basta clicar na correspondente casinha no editor de variáveis. se mostra um diálogo que mostra todos os atributos definidos na base de conhecimento. etc. eventos. No menu contextual depois escolher Add Variável. com suas mesmas características.0) Para percorrer os valores armazenados se deverá criar uma nova variável de tipo Numeric (4. se deve utilizar a estrutura de controle “For in”. ou indicar o valor True na propriedade Collection associada as variáveis. Isto é.). Por exemplo. Por outra lado. temos definido a variável &myNumbers de tipo Numeric(4.0). Quando se seleciona. Variáveis coleção É possível definir variáveis coleção sobre qualquer tipo de dados oferecido por GeneXus.“Based On” Oferece uma forma rápida de definir uma variável. em dito diálogo. Criamos então a variável &OneNumber. criando nesse caso uma variável para cada atributo selecionado. Para percorrer depois os itens colecionados em dita variável. e em seguida se defini automaticamente uma variável com o mesmo nome e a mesma definição que o atributo. simplesmente se deve selecionar um atributo. é possível definir variáveis dentro do editor de código de cada objeto (source. ao escrever &nomeDeVariavel (ex: &x) e pressionar botão direito do mouse. fazendo uso do menu contextual (botão direito) depois de escrever o nome da variável. Vale declarar que se podem selecionar vários atributos.

como atributos do tipo numérico e tamanho 10. que seja do tipo numérico com tamanho 10. ou todos os valores. a mudança é realizada uma única vez (no domínio Price). e a cada um dos atributos mencionados atribuir o domínio valores Price. mas que não tenham nenhuma relação. como atributos do tipo character e tamanho 20. Como exemplo. Desse modo. na mesma base de conhecimento. Exemplo: Atributos ProductPrice InvoiceDetailAmount Preço do produto Valor total da linha Domínios É comum ter numa base de conhecimento. Por exemplo.2. assim como o atributo ProductPrice que é do mesmo tipo e tamanho. O objetivo dos domínios é permitir realizar definições genéricas. 50 . propagando-se este automaticamente aos atributos InvoiceDetailAmount e ProductPrice. é comum definir todos os nomes. A vantagem de fazê-lo assim. atributos que compartilhem definições similares.2. o atributo InvoiceDetailAmount é do tipo numérico e tamanho 10. é que se no futuro surgir a necessidade de mudar a definição dos atributos que representam valores.2. podemos definir um domínio de nome Price.Transações Domínios • Objetivo: Realizar definições genéricas. • Quando os domínios devem ser utilizados? • Atributos e/ou variáveis com a mesma definição.

quando se precisa que uma variável tenha um dos seguintes valores: Segunda-feira. mas apenas 3: A. Já tínhamos outro atributo com domínio enumerado: CustomerGender. Quinta-feira.Transações Domínios • Domínios enumerados: manter o estado do cliente: Active. que corresponde ao tipo de dados Character(1) mas para o qual explicitamente dizemos que não queremos que possa ter todos os valores desse tipo de dados. Isto fará sentido quando vermos o Form de uma transação um pouco mais adiante. 51 . Closed dominio Status Atributo CustomerStatus de domínio Status Se trabalha com os nomes ao invés de trabalhar com os valores: CustomerStatus = Status. Uma forma de representá-lo é definindo um domínio Status. on hold ou closed. On Hold. H e C. H ou C. Terça-feira. Sexta-feira. Quarta-feira. Em nosso caso. ao H ‘OnHold’ e ao C ‘Closed’. possuía apenas 2 valores: Female e Male.Active Existe a possibilidade de trabalhar com domínios enumerados (aqueles que representam valores finitos e particulares). porém. ao inserir o atributo na estrutura depois de ter definido o domínio isto é automaticamente sugerido pelo GeneXus) no atributo da tabela internamente será salvo um dos 3 valores: A. Assim. mas sim seus códigos: Active. Nesse caso. Domingo. não teremos de lembrar esses valores. Sábado. Associando ao atributo CustomerStatus o domínio Status (observar que. ao A associamos o nome ‘Active’. Observar como o Control Info oferece para o ControlType um Combo Box ao invés de um Edit. Pode estar active. devido à terminação do nome do atributo. OnHold e Closed. Nas linguagens de programação são bem conhecidos. e dizemos também que queremos trabalhar dando nomes a estes 3 valores e trabalhar com seus nomes. vamos adicionar à estrutura da transação Customer um atributo que representa o estado do cliente no sistema num determinado momento. O caso típico de uso é para os dias da semana.

2) sobre a coluna Type do atributo que se está definindo. já que o objetivo é exatamente o mesmo. o nome do domínio. Por exemplo. Como definir um domínio? Existem vários caminhos: 1) Opção Domains do Folder View: Mediante um editor similar ao das variáveis. 52 . pode ser definido um novo domínio. se oferece um botão para criar um domínio novo. Idem com o diálogo de definição de variáveis. simplesmente escrevendo sobre essa mesma linha.2). digitando Price = Numeric(10. 3) Na estrutura da transação é possível definir um novo domínio no campo de definição do tipo de dados de um atributo.Transações Domínios Assim como o domínio pode ser associado a um atributo (e a outro domínio). com o tipo de dados Numeric(10. e atribuindo o tipo de dados. 2) Visto que na tela de configuração das propriedades de um atributo é onde se atribui a um atributo um domínio existente. em dita tela. Um mesmo domínio pode ser referido tanto a atributos como a variáveis. fica também definido o domínio de nome Price. da mesma forma pode ser associado a uma variável.

e contem todos os atributos incluídos na mesma. É criado por default por GeneXus ao momento de gravar a estrutura da transação. agregar e/ou tirar botões. que será a interface com o usuário. mudar por exemplo controles de tipo edit a outros tipos de controles. GeneXus cria um form web. podendo ser modificado pelo programador. etc. Se bem é criado por default. Por default é criado ao gravar a estrutura da transação.Transações Web Form Cada transação tem um Web Form. é possível modificá-lo para deixá-lo mais vistoso. além de alguns botões. com suas respectivas descrições. 53 . Para cada transação.

54 . seu tipo de letra. cor. Poderemos especificar entre outras coisas o lugar onde queremos que este controle esteja dentro do form. modificar e eliminar faturas na aplicação Web.Transações Web Form da transação “Invoice” Control “Error Viewer” GRID No exemplo que se mostra o form Web correspondente a transação “Invoice”. Através deste form o usuário final poderá ingressar. Observe que o segundo nível da transação aparece no form como um control grid. O controle Error Viewer se utiliza para poder colocar e programar no lugar onde queremos que as mensagens gerais sejam mostradas ao usuário final de uma transação Web. etc..

Transações Web Form da transação “Customer” Domínios básicos controles Edit Domínios enumerados controles Combo Box 55 .

Botão: Permite incluir botões nos forms. Simplesmente se deve selecionar o controle e arrastá-lo sobre o form. . se encontra disponível uma paleta de ferramentas (Toolbox) que oferece os controles possíveis de inserir no mesmo. etc.Linha horizontal . Paleta de ferramentas para inserir controles: Quando se está editando um form.Texto: Permite colocar texto fixo . Existem diferentes controles: . 56 .Error Viewer . copiar e colocar controles: Podemos definir um controle como uma área da interface com o usuário.Grid: Permite definir grids de dados.Tabela: Inserir tabelas no form . que tem uma forma e um comportamento determinado.Transações Paletas de ferramentas para o desenho de Forms Inserir controles: • Opção View do Menubar \ Other Tool Windows \ Toolbox Cortar. . .Bitmap: Permite definir bitmaps estáticos.Atributo/Variável: Permite colocar atributos ou variáveis.

Isto permite que o desenho da interface seja independente da programação. Ao criar uma KB. • O analista somente associa um tema ao objeto. O controle herda o desenho da classe do tema associado. permitindo ao programador aproximar-se das tarefas de programação. se cria por default o tema “GeneXus X” e todos os objetos criados terão este tema associado. Um objeto “tema” conterá um conjunto de classes. • • • Para separar os aspectos de desenho gráfico de um site web. dos aspectos de programação propriamente dito. 57 . Este tema contem um conjunto de classes associadas aos diferentes controles existentes. Desta maneira o design gráfico configurará o “tema” escolhido pelo programador. e apoiar-se em um design gráfico para que defina as questões de desenho. algumas para o controle atributo. e cada controle que apareça em seus forms terá associado uma classe desse tema.Transações Controles em Web Form • Cada controle do Web form pode ter associada uma classe. etc. terá várias classes para o controle botão. • Cada tema vai ter muitas classes definidas para cada tipo de controle. Os objetos com form Web que vão sendo criados terão por default associado este Theme. Quando se cria uma base de conhecimento. automaticamente aparecerá dentro do Folder View da pasta “Customazation” com objetos Theme pré-definidos que poderão ser importados na KB. Por exemplo. existe um tipo de objeto chamado Theme (Tema em português). e uma classe a cada controle do form e não precisa se preocupar com o desenho dos mesmos. O objetivo desta separação é paralelizar o desenvolvimento de um site Web. uma classe para o controle Error Viewer. para este controle. Por default se importa o de nome “Genexus X”. para cada tipo de controle dos que podem aparecer no form Web de um objeto GeneXus. de um objeto theme (tema) determinado que está associado ao objeto. e o programador somente deverá aplicá-lo aos objetos de sua base de conhecimento.

quando o analista cria a transação "Customer“ e informa sua estrutura. Quem deu o formato a todos os controles se não foi o analista exatamente? Pois bem. Se sobre o Text Bloxk (controle de texto) mostrado acima (Name). todas as transações terão associado por default o tema “GeneXus X” e todos os controle colocados no form.Transações Controles em Web Form Deste modo. terão classes deste tema associadas. 58 . Ao clicar o combo box poderemos ver uma lista de classes possíveis para esse controle (são as que figuram no tema associado). Não entraremos em detalhe neste tema no presente curso. pode-se observar a propriedade Class. se editam suas propriedades (F4). A direita mudamos a classe para uma de nome Title e no form podemos ver a repercussão no desenho do TextBlock. Esta propriedade pode ser mudada pelo analista. ao gravá-la pode ver que o Form Web terá automaticamente o aspecto mostrado na tela acima à esquerda. que tem configurada a classe TextBlock.

ou pressionar a tecla F5. Server name: Nome do servidor da base de dados que a administra. se indicou o gerador por default a ser utilizado. sempre e quando o usuário e contrasenha configurados na janela de diálogo tenham permissão de DBCreator no DBMS. GeneXus a criará. 59 . Agora deve completar a informação necessária para terminar de definir o ambiente de implementação. F5: Dispara automaticamente todas as ações necessárias para executar a aplicação Se BD não existe. Database name: Nome da base de dados que estará associada a aplicação. se cria automaticamente (sempre e quando usuário e password tenham permissão de DBCreator) Lembremos que no momento de criação da KB. Use trusted connection: Yes (deverá indicar o usuário e contra-senha válido no DBMS) No Considerações: Se a base de dados não existir.Demo Como executar a aplicação? Opção Build \ Run Developer Menu.

permitindo realizar outras tarefas enquanto o mesmo estiver correndo. Este nome é auto-descritivo: GeneXus analisa o impacto causado pelas novas definições. por exemplo continuar com o desenvolvimento.Processo de Build O processo de Build inclui todas as tarefas necessárias para a execução da aplicação: Verificação de alterações na BD. Não inclui a execução. Cada vez que se executa a aplicação (F5). isto provocará (tal como é o objetivo das transações) que se criam as tabelas correspondentes na base de dados (ver página seguinte). Especificação. e o resultado da análise de impacto é um relatório de análise de impacto (IAR: Impact Analisis Report) que informa ao programador quais alterações físicas ou estruturais precisam ser realizadas na base de dados associada. Reorganização (se for necessário). 60 . se chama análise de impacto. GeneXus realiza uma comparação entre as definições atuais de todos os objetos e as definições da última execução. Geração e Compilação. KB DBASE IMPACT ANALYSIS REORGANIZATION SPECIFICATION GENERATION Aplicação pronta para executar COMPILATION APPLICATION O processo de Build é executado em background. Esta comparação que o GeneXus faz. Se por exemplo se criou uma nova transação.

Quando se decide efetuar uma reorganização GeneXus gera programas (na linguagem escolhida quando se criou a KB) que implementam as modificações a serem realizadas na base de dados. Gerar um objeto. na qual informará a lógica interpretado. criar as 2 transações “Customer” e “Invoice” e dar F5. Compilar os programas significa que o código escrito (gerado) seja convertido a linguagem de máquina (binário) para que possam ser executados. O término reorganizar refere a efetuar alterações físicas na base de dados. e as redefinições convenientes são criadas. a estrutura que terá cada tabela que será criada. significa que GeneXus escreverá linhas de código que implementem a programação do mesmo. Se o programador está de acordo com os alterações estruturais informadas no relatório de análise de impacto. ou outros elementos segundo corresponda.IAR e Reorganização ‘Create’ se estiver tudo OK serão construídos os programas no Environment e vai executar. aparece o relatório de análise de impacto que pode se ver. Para isso GeneXus deverá especificar. poderá não efetuar a reorganização. a validez do definido. O seguinte passo será obter os programas da aplicação associados aos objetos GeneXus. e como resultado da especificação mostrará ao usuário uma listagem de navegação. Especificar um objeto significa que GeneXus analisará tudo o que foi definido em cada um dos elementos que o compõem: estrutura. onde são listados entre outras coisas.. as chaves estrangeiras (observar que o relatório da tabela INVOICE diz que se referenciará a tabela CUSTOMER (isto acontece pelo atributo CustomerId da transação Invoice que se chama igual que o atributo CustomerId de CUSTOMER. poderá prosseguir. na linguagem escolhida. com seus atributos. gerar e compilar os programas da aplicação. A execução destes programas tem como resultado a obtenção de uma nova versão da base de dados com as alterações efetuadas. constituindo portanto uma chave estrangeira a dita tabela). GeneXus verificará a sintaxe das definições. passando a reorganizar a base de dados. os índices que serão criados sobre as tabelas. Se na alteração o programador encontra algo informado no relatório de análise de impacto não era o que pretendia obter. e se tem alguma advertência ou erro.. tipo de dados. forms. 61 . No exemplo.

Execução 62 .

.Opção “Build” da barra do menu de GeneXus Opções do item “Build”: • Build All e Rebuild All: Estas opções são utilizadas quando não se está seguro do impacto das alterações e se quer ter atualizadas as últimas definições. . . enquanto que Rebuild All força todas elas.Gera os objetos. se for necessário.Gerar os objetos .Reorganizar a base de dados.Compilar os objetos definidos Main . A opção Build All realiza todas as ações que estejam pendentes.Reorganizá-la a base de dados.Especifica somente os objetos que foram modificados. .Salva todos os objetos que não estejam salvos. . 63 . Não o executa. • Run Developer Menu: Executa todas as ações que estejam pendentes e executa o Developer Menu.Especificar somente os objetos que foram modificados (se selecionou Build All). .Compila e executa o Developer Menu.Salvar todos os objetos que não estejam salvos. As ações são: . ou forçar a especificação de todos (selecionou Rebuild All). .Compilar o Developer Menu • Build / Rebuild Developer Menu: Similar as opções anteriores mas aplicadas somente ao Developer Menu. . se for necessário.

ou se força a especificação de todos os objetos pertencentes a árvore de chamadas do objeto Main (quando selecionado Rebuild).Salvam todos objetos que não estejam salvos. .Execução do objeto Main (quando selecionado a opção Run) • Build / Run with this only options: Build e execução do objeto definido como Startup. • Impact Database Tables: Se realiza um impacto sobre as tabelas da base de dados.Compilação do objeto Main .Se executa o objeto Startup (se selecionou Run). Por default o objeto Startup é o Developer Menu. Se perdem os dados que poderão estar armazenados previamente. se for necessário. 64 . ou seja o objeto que finalmente se executa quando se pressione a tecla F5.Reorganização a base de dados. Por default o objeto Startup é o Developer Menu.Reorganização a base de dados.Especificam somente o objeto selecionado.Geração .Salvam os objetos que não estejam salvos. . se for necessário. . .Geram somente o objeto selecionado. Disparam as seguintes ações: . .• Build / Rebuild / Run options: Opções aplicadas a objetos definidos como Main.São especificados somente os objetos que sofrerem alterações (se selecionou Build). .Compilam o objeto Startup . • Set As Startup Object: O objeto indicado passará a ser o objeto Startup da aplicação. . . • Create Database Tables: Cria novamente as tabelas.

ou consulta da base de dados através de uma transação. 65 . dependendo da operação que se realize: Modo Insert: Indica que se está efetuando uma inserção Modo Update: Indica que se está efetuando uma atualização Modo Delete: Indica que se está efetuando uma eliminação Modo Display: Indica que se está efetuando uma consulta Dependendo do ambiente de geração. eliminação.Transações Modos em tempo de execução • Os diferentes modos podem ocorrer ao executar uma transação. cada vez que se realize uma operação de inserção. atualização. Diante da plataforma. existem um modo associado. existem algumas diferenças referentes à operacionalidade das transações em tempo de execução.

Depois deve pressionar o botão Confirm. Se o usuário ingressou as 5 linhas e necessita ingressar mais. 66 .Transações Em tempo de execução &GxRemove: Variável do sistema para eliminar linhas. em forma de check box. Por default são mostradas 5 linhas vazias. Para agregar uma nova linha Sempre vai mostrar um número de linhas vazias fixas para ser ingressadas pelo usuário (valor configurável pelo analista a nível do grid. Para poder eliminar linhas em execução. Para visualizar este check box. bastará pressionar New Row. GeneXus incorpora automaticamente no grid do form Web uma primeira coluna com uma variável do sistema de nome &GxRemove. ou simplesmente pressionar Enter e uma nova linha é agregada. se deve pressionar o botão direito do mouse sobre a linha a ser eliminada. em sua propriedade “Rows”).

Isso se faz no controle presente no form de nome Content Placeholder. Ao criar uma base de conhecimento GeneXus X cria também dois objetos de tipo Master Page: AppMasterPage: Para a aplicação. Quando estudarmos o objeto Web Panel compreenderemos que uma Master Page será em particular uma Web Panel categorizado como “Master Page” com todo o Layout e comportamento comum a todas as páginas do site. Criadas automaticamente automaticamente com a KB Ter um look&feel consistente é hoje em dia um dever de toda aplicação Web. 67 . dentro deste objeto se deixa um espaço para carregar em cada oportunidade a página que corresponda (o conteído variável do site). Isto significa que a modificação de alguma parte do layout ou do comportamento comum é tão fácil como modificar em um único objeto e pronto! Em uma mesma base de conhecimento podem ser definidas quantas Master Pages como se deseje. PromptMasterPage: Para os prompts. Criar e manter cada página de uma aplicação Web assegurando a consistência com o resto do site toma grande tempo de programação.Transações Master Pages As Master Pages fornecem uma forma de centralizar o layout e o comportamento comum em somente um objeto e reutilizá-lo em qualquer outro objeto sem ter que programar. As Master Pages fornecem uma forma de centralizar o layout e o comportamento comum em um objeto somente e reutilizá-lo em qualquer outro objeto sem ter que programar.

carreguem com esse “contexto” (o da Master Page). se associam a Master Page. 68 .Transações Master Pages • Propriedade Master Page As páginas web que implementam o conteúdo variável. de maneira que cada vez que sejam executadas.

ProductId}. o atributo ProductId sozinho. Depois do F5. criando a tabela PRODUCT e modificando a tabela INVOICEDETAIL da maneira que indicamos nos parágrafos anteriores. A chave primária da tabela INVOICEDETAIL continua sendo composta: {InvoiceId. será uma FK na tabela PRODUCT. mas além disso. O que acontecerá se existia o mesmo produto em várias linhas de diferentes faturas? 69 . através da nova chave estrangeira ProductId. para os que possuiam valores de ProductDescription e ProductPrice? Como será visto quando executar. antes próprios da tabela INVOICEDETAIL.Demo • Agregar a transação “Product” que não foi definida e ver como ficam os ícones em “Invoice” O que acontece ao fazer F5? Observe como depois de criar a transação “Product” GeneXus normaliza e indica graficamente na estrutura da transação “Invoice” que os atributos. agora serão inferidos. O que acontece com os registros já existentes na tabela INVOICEDETAIL. naturalmente será informado a necessidade de reorganizar a base de dados. o programa de reorganização agrega uma rotina para criar os registros de produtos na tabela PRODUCT com essa informação pré-existente. a partir da qual se inferem os atributos ProductDescription e ProductPrice.

INTEGRIDADE REFERENCIAL 70 .

a seta simplesmente representa a existência de uma instancia da tabela mostrada. Reciprocamente. No Diagrama de Bachman. ou seja. CountryId) Chave Primária: CustomerId Chave Estrangeira: CountryId (COUNTRY) CustomerAddress. Dizemos que a relação entre a tabela COUNTRY e a tabela CUSTOMER é 1 de N (1 a muitos). Se refere que deve fazer a consistência entre os dados das diferentes tabelas de uma base de dados relacional. a relação entre CUSTOMER e COUNTRY é N de 1 (muitos a 1). O fato do atributo CountryId está na tabela CUSTOMER ser uma chave estrangeira com respeito a tabela COUNTRY. CustomerName. CountryName) Chave Primária: CountryId CUSTOMER (CustomerId. Estas relações implicam que os dados das tabelas não sejam independentes. para cada instancia de outra tabela (para cada país. para cada instancia da outra (para cada cliente existe um e somente um país). As tabelas de uma base de dados relacional estão relacionadas por atributos que tem em comum. A seta dupla representa a ocorrência de várias instâncias da tabela apontada. 71 . ao inserir. A relação entre elas pode ser representada com o diagrama mostrado. CustomerGender. modificar ou eliminar registros de uma tabela tem que ser levado em consideração os dados das outras tabelas para que sempre se conserve a consistência da informação na base de dados. Se temos um modelo de dados relacional com as tabelas: COUNTRY (CountryId.Integridade Referencial Diagramas COUNTRY 1 CountryId* CountryName CUSTOMER N CustomerId* CustomerName ……… CountryId O conceito de integridade referencial é um conceito que se refere às bases de dados relacionais. existem muitos clientes). estabelece uma relação entre ambas as tabelas.

A estes controles se chama de Integridade Referencial e basicamente são os seguintes: • Quando se insere ou modifica um registro na tabela CUSTOMER. Devido a esta relação entre as tabelas.Integridade Referencial Diagramas COUNTRY 1 N Tem que verificar existência do COUNTRY referenciado. Por esta razão. não devem existir registros relacionados na tabela subordinada (CUSTOMER). ou • se modificar o CountryId de um registro COUNTRY 1 N Na transação “Country”: • se quer eliminar um registro CUSTOMER Tem que verificar se não existe nenhum CUSTOMER que o referencie. deve existir como valor de chave primária de um registro na tabela COUNTRY. • Quando se elimina um registro na tabela superordinada (COUNTRY). e é necessário realizar controles para que os dados sejam consistentes. o valor ingressado no atributo que é chave estrangeira (CountryId). não devem existir registros na tabela CUSTOMER cujos valores da chave estrangeira (CountryId). Na terminologia GeneXus. dizemos que existe uma relação de subordinação entre ambas as tabelas. a informação contida nelas não é independente. • Quando se elimina um registro na tabela COUNTRY. Dizemos que: COUNTRY está superordinada a CUSTOMER CUSTOMER está subordinada a COUNTRY Significando que: Quando se cria ou modifica um registro na tabela subordinada (CUSTOMER). deve existir o registro relacionado na tabela superordinada (COUNTRY). •GeneXus gera os programas associados as transações. uma mensagem é mostrada ao usuário indicando que não se encontrou esse país. sejam iguais ao valor da chave primária do registro que se deseja eliminar. 72 . exista como chave primária de um registro na tabela COUNTRY. CUSTOMER Na transação “Customer”: • se inserir um novo registro. Em caso de falhar este controle de integridade referencial. se o usuário final insere (ou modifica) um cliente através da transação "Customer". incluindo no código gerado estes controles de Integridade Referencial. é validado automaticamente que o valor ingressado no código de país CountryId.

Existe entre estas tabelas uma relação 1-N. são criados ao executar as aplicações. os únicos que não são criados automaticamente por GeneXus são os “de usuário”. são utilizados e depois são eliminados.Integridade Referencial Índices Os índices são vias de acesso eficientes as tabelas.Os índices primários e estrangeiros são criados no momento de criar ou reorganizar as tabelas que compõem a base de dados. baseando-se em critérios de otimização. para acessar a tabelas ordenadas por algum atributo ou conjunto de atributos para ele/eles que não existe um índice de usuário criado. Existem quatro tipos de índices em GeneXus: • Primários • Estrangeiros • De usuário •Temporários De todos eles. a diferença que existe entre eles é o momento em que são criados e o tempo durante o qual se mantêm. criadas em nosso modelo de dados a partir das estruturas das transações "Country" e "Customer”. sendo que depois devem ser mantidos? Sejam as tabelas COUNTRY e CUSTOMER. GeneXus cria automaticamente alguns deles.Os índices temporários. Enquanto aos tipos de índices que são criados por GeneXus. ÍNDICES PRIMÁRIOS E ESTRANGEIROS GeneXus cria para cada tabela um índice por sua chave primária (índice primário). que ocorre pelo fato de que o atributo CountryId na tabela CUSTOMER é uma chave estrangeira com respeito a tabela COUNTRY. 73 . por sua vez. estes se criam em tempo de execução das aplicações. que vimos um par de páginas atrás. e um índice por cada chave estrangeira que a tabela tenha (índices estrangeiros). . e depois são mantidos automaticamente por GeneXus. . Por que criar índices primários e estrangeiros para as tabelas no início de forma automática. e outros deverão ser criados pelo programador quando este assim o determine.

sendo que. será indicado ao usuário que não é possível eliminar o país (já que do contrário ficariam dados inconsistentes na base de dados). o GeneXus ao criar cada tabela da base de dados. isto é.. a busca pode ser otimizada se existir um índice pela chave primária em dita tabela. Para controlar isto. devemos consultar a tabela CUSTOMER. é validado automaticamente que o valor ingressado para a Chave Primária. Para fazer esta busca com eficiência. Esta busca será otimizada se existir um índice por CountryId na mesma. devemos utilizar o índice primário da tabela. não exista como Chave Primária de outro registro na tabela. Estes controles são: • Se o usuário final insere ou modifica um cliente através da transação "Customer". buscando pela chave estrangeira CountryId. os controles de integridade referencial pertinentes. deve-se buscar na tabela COUNTRY a existência de um registro que tenha esse valor de CountryId como chave primária. FK ICustomer1 CountryId PK CountryId CountryName 1 2 3 Uruguay United States China CustomerId 4 1 3 2 CustomerName Ann Silver John Smith Mary Jones Jessica Deep CountryId 1 1 1 2 Se na transação “Country” queremos eliminar “United States”: O programa deve buscar sobre CUSTOMER se existe registro com CountryId = 2 para que essa busca seja eficiente: índice estrangeiro (ICustomer1) Por existir esta relação.Integridade Referencial Índices primários e estrangeiros CountryId* CountryName PK ICountry ICustomer CustomerId* CustomerName . Caso o controle de integridade referencial falhe é indicado ao usuário que não foi encontrado este país. será validado automaticamente assim que o valor ingressado na chave estrangeira CountryId exista como chave primária de um registro na tabela COUNTRY. 74 . • Se o usuário final tentar eliminar um país através da transação "Country" é validado automaticamente que não existam clientes no país atribuído com chave estrangeira. e um índice estrangeiro por cada Chave Estrangeira que a tabela contenha. devemos consultar a tabela COUNTRY. cujo valor de chave estrangeira CountryId seja o que se deseja eliminar. em nenhuma tabela poderão existir dois registros com o mesmo valor na Chave Primária. Para controlar isto. Controle de unicidade de chave primária Outro controle que o GeneXus também inclui nos programas associados às transações é a unicidade da Chave Primária. Para controlar isto. buscando pela chave primária. quando o usuário final tentar inserir um registro. cria também seu índice primário. o GeneXus inclui nos programas associados às transações "Country" e "Customer". A criação destes índices permite realizar os controles de integridade referencial e de unicidade de chave primária acessando as tabelas de forma eficiente. em caso de encontrar um registro na tabela CUSTOMER. Concluindo..

Um índice de usuário unique é utilizado para especificar que um conjunto de atributos é chave candidata em uma tabela (diferente da chave primária). supondo que o nome do cliente não é chave na tabela de CUSTOMER (seus valores podem se repetir) poderemos definir um índice de usuário duplicate para o atributo CustomerName. se o nome do cliente não pode ser repetido. Não são definidos automaticamente. Por exemplo. Deve ser categorizado conforme for aceito valores repetidos (duplicate) ou não (unique). • Se na realidade modelada. Este tipo de índices se define fundamentalmente para acessar os dados ordenados por determinados atributos de forma eficiente. dois clientes podem ter o mesmo nome: CustomerId 1 2 3 CustomerName Ann Ann Mary CountryId 1 2 1 ÍNDICES DE USUÁRIO Estes índices devem ser definidos explicitamente pelo analista. se define para atributos que não são uma chave candidata).Integridade Referencial Índices de Usuário • O analista os cria sobre uma tabela. Esta é a forma de representar chaves candidatas no modelo de dados. Com isso conseguimos que o GeneXus incorpore automaticamente o controle de unicidade correspondente nas transações associadas. Por exemplo. Dividem-se em duplicate e unique: Um índice de usuário duplicate é definido para atributos de uma tabela que possam ter vários registros com o mesmo valor nos mesmo (isto é. 75 . a forma de representá-lo e fazer com que o GeneXus o controle automaticamente é definindo na tabela CUSTOMER um índice de usuário unique pelo atributo CustomerName. sendo muito útil para realizar consultas e relatórios que necessitem que sejam ordenados por nome.

o GeneXus cria automaticamente um índice primário para dito atributo e controla a unicidade dos valores ingressados para o mesmo. Neste caso tanto o atributo CustomerId como o atributo CustomerSSN (armazena o Nro da Carteira de Identidade) seriam chaves da tabela CUSTOMER. A forma de definir em GeneXus que um atributo ou um conjunto de atributos é Chave alternativa ou candidata e que para tanto deve-se checar sua unicidade. queremos que o GeneXus garanta da mesma forma. GeneXus inclui na lógica da transação esse controle de unicidade utilizando esse índice definido pelo usuário. Para poder fazer este controle de forma eficiente. as transações GeneXus realizam automaticamente os seguintes controles: . Índices unique (chaves candidatas) Em uma tabela da base de dados podem existir vários conjuntos de atributos cujos valores sejam únicos na realidade. Em resumo. para não permitir a inserção de registros duplicados. o analista escolhe uma das chaves como a chave primária. Ao indicar que CustomerId é o identificador da transação. A partir daí. já existindo outro com o mesmo valor da carteira de identidade (CustomerSSN). Ao tentar ingressar um novo cliente com nome “Ann Jones” a transação dará um erro de registro duplicado. Integridade referencial .Integridade Referencial Índices de Usuário • Se o nome não pode ser repetido (é portanto um atributo chave da tabela) CustomerId 1 2 3 CustomerName John Smith Ann Jones Richard Land CountryId 1 2 1 • A forma de definir chaves candidatas no modelo de dados é através de índices unique. não permitindo que seja inserido um registro. O que acontecerá com a carteira de identidade do cliente? Ao ser este atributo chave. e o qualificando como “unique” ao invés de “duplicate”. é definindo um índice de usuário composto por esse atributo ou conjunto de atributos. Depois. Vamos supor que na realidade além de poder identificar um cliente por seu código ou possa ser identificado por sua carteira de identidade. utilizando o índice. o GeneXus deveria ter um índice para cada atributo chave. Unicidade de chave (tanto primária como candidatas) 76 . GeneXus identifica a chave primária da tabela de acordo com os atributos que foram qualificados pelo analista com o símbolo da chave. Dizemos que cada um desses conjuntos é uma chave da tabela. GeneXus passará a incorporar controles nas transações. que é o valor por default de um índice de usuário.

as consultas para as quais se quer obter o resultado ordenado por determinados atributos. • Em algumas plataformas. então. um índice temporário é criado. porque se trata de uma consulta que se realiza com pouca freqüência).Integridade Referencial Índices Temporários • São criados automaticamente. • O usuário pode resolver deixar de utilizar um índice temporário. e não existe o índice de usuário. mas não se deseja criar um índice permanente para ele (por exemplo. quando são necessários. ÍNDICES TEMPORÁRIOS Quando se deseja acessar os dados ordenados por determinados atributos. dependendo da plataforma. mas não se deseja criar um índice permanente para ele: GeneXus cria um índice temporário. sob certas condições. criando um índice de usuário. 77 . e são eliminados quando termina a execução do objeto que os criou. • Se deseja acessar os dados ordenados por determinados atributos. são resolvidos pelo DBMS correspondente sem a criação de índices temporários.

Resumindo: o objetivo desta propriedade é definir qual valor vai ser armazenado na base de dados quando não for digitado nada no campo (o valor <NULL> ou o valor empty). não inferidos) sempre e quando não forem atributos primários nestas tabelas (já que por definição as chaves primárias não suportam valor null). e que não seja o identificador na estrutura de uma transação. Os atributos que podem ser configurados desta forma. A propriedade Nulls (apresentada como coluna no editor de estrutura de transações). um valor válido deve sempre ser atribuído a ele. são aqueles armazenados nas tabelas associadas na transação (isto é. ser “ignorado” visto que é “valor não especificado”. Permitir o valor null para um atributo dado. permite configurar para cada atributo se admite ou não valor null na tabela associada.Integridade Referencial Gerência de nulos • Para cada atributo não inferido. significa que pode em certas circunstâncias. Por outro lado. 78 . o atributo não permitindo valor null. é possível definir para a tabela associada se vai ser nulo ou não A permissão ou não do valor <NULL> na base de dados é muito importante no modelo relacional.

Integridade Referencial Gerência de nulos • A propriedade Nulls aceita os seguintes valores: . Ou seja que modificar o valor da propriedade Nulls para um atributo vai implicar em executar uma reorganização (para redefinir a nível da base de dados o suporte de nulabilidade do atributo em sua tabela). sempre) • Atributos da chave estrangeira aceitam nulo e isto repercute nos controles de integridade referencial. O atributo na tabela associada. admitirá valor null • Atributos que fazem parte da chave primária não suportam valor null (propriedade Nulls = No. já que o suporte ou não suporte de nulabilidade dos atributos em sua tabela. Os valores possíveis de serem configurados para essa propriedade Nulls são: No: significa que o atributo não permite o valor null na tabela associada (valor por default) Yes: significa que o atributo permite o valor null na tabela associada. 79 .No: Valor por default. A definição de nulls é utilizada por GeneXus no momento de criar/reorganizar as tabelas da base de dados.Yes: o atributo na tabela associada. não permitirá valor null . se define a nível da base de dados.

Se nenhuns dos atributos que compõem uma chave estrangeira permitem valores nulos (caso 1). se deixar Repercussão em controles de integridade referencial A definição de nulls para atributos que formam uma chave estrangeira diz ao GeneXus quão forte é a referência a outra tabela. já que é estabelecido que a FK deverá sempre apontar a um registro existente da tabela referenciada. para assegurar que o país ingressado esteja correto.Integridade Referencial Gerência de nulos • Repercussão em controles de integridade referencial CountryId* CountryName CountryId* CityId* CityName FK composta CustomerId* CustomerName CountryId CityId 1) CountryId e CityId com propriedade Nulls=No • As checagens de IR mostradas acima são realizadas 2) CityId com propriedade Nulls=Yes • Um controle de IR em CUSTOMER é agreagado nulo CityId. trata-se de uma referência forte (também conhecida como “not null reference”). Outro caso. onde se o usuário deixar nulo o valor de CityId para um cliente. Um exemplo é o apresentado acima. já que se algum dos atributos que formam parte da chave estrangeira são nulls. é se uma chave estrangeira que tenha pelo menos um atributo que suporte nulos (caso 2). realiza checagem contra COUNTRY. se estabelece uma referência fraca (também conhecida como “null reference”). se realizará a checagem de IR contra COUNTRY. 80 . então a referência não será checada. podem aparecer novas referencias (não checadas caso possua referências fortes) se os atributos restantes compõem também uma chave estrangeira. Quando uma chave estrangeira é composta e os nulos são permitidos para alguns de seus atributos.

não é um valor.IsNull(). IsNull: devolvem true quando o atributo contem respectivamente.Integridade Referencial Gerência de nulos • Diferença entre valor empty e null para atributos: • empty: é um valor (0 para Numeric.IsEmpty(). respectivamente. “” para Character. etc. Significa que o valor deve ser considerado como: • • • • não especificado não disponível não atribuído desconhecido • Métodos segundo se o atributo permite null ou empty: • • • • IsEmpty IsNull SetEmpty SetNull Métodos para trabalhar com nulos e vazios IsEmpty. SetNull: configuram no atributo o valor empty ou null. valor empty ou null SetEmpty.) • null: se é permitido. * msg(‘Warning: You didn’t specify a Country’) if ContryId. Exemplos: * error(‘You must specify a name’) if CustomerName. 81 .

TABELA BASE E TABELA ESTENDIDA 82 .

se o seguinte Diagrama representa nosso modelo de dados: para listar as faturas seria necessário consultar as tabelas: INVOICE e INVOICEDETAIL (linhas de faturas). por exemplo. mas que deve ser considerado também alguns inconvenientes. devemos consultar uma quantidade importante de tabelas. sua tabela estendida alcançará todos os atributos da própria tabela base. COUNTRY e PRODUCT. Uma base de dados desenhada desta maneira tem uma série de vantagens importantes (tanto é assim que atualmente a normalização de dados é um padrão de desenho). Assim.Os critérios de normalização do desenho da base de dados servem para minimizar a possibilidade de inconsistência dos dados. Para simplificar esta tarefa GeneXus utiliza o conceito de tabela estendida. e dada certa tabela base. O inconveniente mais notório é que os dados se encontram dispersos em muitas tabelas. direta e indiretamente). e muitas vezes quando se quer realizar consultas mais ou menos complexas à base de dados. 83 . Chamamos tabela base a qualquer tabela da base de dados na qual estamos posicionados em determinado momento. mas todos os atributos das tabelas que tenham informação relacionada unicamente com a tabela base (relação N-1 desde a tabela base. CUSTOMER.

Todas as tabelas as quais se pode chegar seguindo as setas que representam relações N-1 da tabela base. O seguinte quadro mostra a tabela estendida correspondente a cada uma das tabelas de nosso modelo de dados: 84 . devem-se seguir as relações N-1 (devem-se seguir as setas que tem ponta dupla partindo da tabela base e ponta simples no outro extremo).Tabela Base e Tabela Estendida INVOICE InvoiceId* InvoiceDate CustomerId CUSTOMER CustomerId* CustomerName CountryId COUNTRY CountryId* CountryName INVOICEDETAIL InvoiceId* ProductId* InvoiceLineQuantity InvoiceLineAmount PRODUCT ProductId* ProductDescription ProductPrice ProductStock Utilizando o diagrama é fácil determinar qual é a tabela estendida correspondente a uma tabela base qualquer: Partindo da tabela base. formaram parte de sua tabela estendida.

No objeto transação as regras cumprem um rol muito importante. ___________________________________________________________________________ 1 Todas as regras das transações podem utilizar atributos das tabelas base associadas a transação. o mesmo deve estar incluído na estrutura da transação (seja que pertença a alguma das tabelas base associadas da transação ou as suas tabelas estendidas).Regras • São utilizadas para definir o comportamento das transações. constantes e funções. são locais. Podem envolver os atributos definidos na estrutura da transação¹.). 85 . já que permitem programar seu comportamento (por exemplo: atribuir valores por default. etc. São escritas de forma declarativa. • Programação DECLARATIVA. variáveis. a ordem em que se escreve não significa a ordem de execução. constantes e funções. Para um atributo poder ser referenciado em regra. ou seja. ou seja. definir controles sobre os dados. • São LOCAIS a transação. assim como as variáveis definidas dentro do objeto. Somente são válidas dentro da transação na qual estão definidas. • Algumas regras: Default Atribuição Msg Error Noaccept Add Subtract Serial Update • Podem incluir: atributos. e a maior parte delas pode também utilizar atributos das tabelas estendidas de ditas tabelas base.

Isto significa que os atributos inferidos podem ser atualizados em uma transação (sendo necessário os declarar na estrutura). or. Today()). ONDE: • att: é um atributo que pertence a alguma das tabelas base associadas na transação. • exp: é uma expressão que pode envolver constantes. Default( InvoiceLineAmount. • exp: é uma expressão que pode envolver constantes. As regras de atribuição podem ser definidas aos atributos de alguma das tabelas bases associadas a transação. SINTAXE: att | &var = exp [if cond] [on evento / momento de disparo]. a diferença é que ao invés de utilizar a variável do sistema today. mas o usuário final pode alterar esse valor se não for o desejado. a condição é opcional. que permitem definir o momento específico de execução de uma regra. SINTAXE: Default( att | &var. Nota: O tipo de dados da expressão deve coincidir com o tipo de dados do atributo ou variável. se utiliza a função Today que devolve a data correspondente ao dia. e deve ser do mesmo tipo que att ou var. o valor resultante da expressão. incluso de suas estendidas. implica em sua atualização no registro que corresponda. &today ). not) • evento/momento de disparo: é um dos eventos predefinidos do GeneXus disponíveis para regras de transações. ProductPrice*InvoiceLineQuantity). • var: é o nome de uma variável. o valor por default inicialiaza o atributo ou a variável quando está sendo realizada uma inserção através da transação (modo Insert). exp ). • cond: é uma expressão booleana (pode conter os operadores lógicos and. implica sua atualização no registro que corresponda. Como se pode ver. /* Regra definida na transação “Invoice” */ Quando uma linha da fatura é inserida. o valor de uma expressão. A atribuição a um atributo. se sugere o valor de InvoiceDate o valor contido na variável do sistema &today. /* Regra definida na transação “Invoice” */ Análoga a anterior. porque é disparada logo que a chave é informada (já que somente nesse momento o modo é conhecido e esta regra é disparada somente em modo Insert EXEMPLOS: Default( InvoiceDate. se sugere que o atributo InvoiceLineAmount (valor da linha) receba o valor resultante da expressão ProductPrice*InvoiceLineQuantity (preço do produto vezes a quantidade levada do mesmo). 86 . A atribuição a um atributo. FUNCIONALIDADE: Esta regra atribui o valor da expressão exp como valor por default do atributo att ou variável var. ou a suas estendidas (deve estar declarado na estrutura). Esta regra não é válida para atributos que formam parte da chave primária de algum dos níveis da transação. • var: é o nome de uma variável. ONDE: • att: é um atributo que pertence alguma das tabelas base associadas a transação. variáveis ou outros atributos. FUNCIONALIDADE: Uma regra deste tipo permite atribuir ao atributo ou variável que fica a esquerda. se ela não for definida. funções. Default( InvoiceDate. funções. /* Regra definida na transação “Invoice” */ Quando uma Invoice nova é inserida.Algumas regras válidas para transação são: Default OBJETIVO: Permite atribuir um valor por default para um atributo ou variável. a atribuição é realizada sempre. variáveis ou outros atributos. quando a transação é executada em modo Insert. Regra de atribuição OBJETIVO: Permite atribuir a um atributo ou a uma variável.

/*Regra definida na transação “Customer”*/ Se avalia a condição CustomerName. •cond: tipo booleana (que pode conter os operadores lógicos and.isEmpty(). msgId ) if cond [on evento/momento de disparo]. SINTAXE: Error( ‘msg’ | &var | character expresion. /* Regra definida em a transação “Invoice” */ Necessita proibir a eliminação de faturas. evitando a eliminação. podemos utilizar esta regra de atribuição para que o usuário não precise realizar o cálculo. Mostra a mensagem do primeiro parâmetro. que permitem definir o momento específico da execução de uma regra. EXEMPLOS: Error(‘Informe o Nome do Cliente’) if CustomerName. 87 . ONDE: msg. que contêm uma string com uma mensagem de erro a mostrar •character expression: é uma expressão cujo tipo resultante. not) •evento/momento de disparo: é um dos eventos pré-definidos do GeneXus disponíveis para regras de transações. As mensagens de advertência são mostradas no Error Viewer. /* Regra definida na transação “Invoice” */ Se o valor de cada linha de uma fatura é calculado sempre multiplicando o preço do produto vezes a quantidade levada do mesmo. mas a diferença desta última. analogamente a regra Error. Não permite continuar até que o usuário ingresse um nome no campo CustomerName ou abandone a transação (nesse caso não é realizada nenhuma atualização na base de dados). character expresion. se a condição é satisfeita. se o usuário tentar realizar uma eliminação. ao disparar o error. Serve para definir os controles que os dados devem cumprir. Error OBJETIVO: Permite mostrar uma mensagem de erro se a condição seja satisfeita. e se for satisfeita. Error(‘Fatura não pode ser eliminada’) if Delete. Com esta regra. se a condição cond avaliada resulta como verdadeira. Quando a transação é executado como business component (estudaremos este tema mais adiante). a condição dará True e se dispara a regra. ONDE: • msg: é uma string com uma mensagem de error a mostrar • var: é o nome de uma variável de tipo caractere. gera um entrada no SDT messages. com identificador msgId. or. msgId. detendo qualquer atualização na base de dados.isEmpty(). se disparar a regra gera entrada no SDT messages. msgId) if cond [on evento/momento de disparo]. mostra a mensagem ‘Informe o Nome do Cliente’ na tela. Do mesmo modo. evento/momento de disparo: são os mesmos que para a regra error. FUNCIONALIDADE: Esta regra se utiliza para apresentar mensagens de advertência ao usuário. Observar que a sintaxe é exatamente a mesma. A mensagem de erro aparece em uma tela pop-up quando o ambiente de trabalho é Windows e no controle Error Viewer e/ou um quadro texto quando o ambiente de trabalho é Web. se a transação é business component1. var. permite continuar com a execução se a condição segue sendo satisfeita.EXEMPLO: InvoiceLineAmount = ProductPrice * InvoiceLineQuantity. __________________________________________________________________________________________ 1 Este tema será visto mais adiante no curso. Msg OBJETIVO: Permite mostrar uma mensagem de advertência se a condição for satisfeita SINTAXE: Msg( ‘msg’ | &var | character expresion. FUNCIONALIDADE: Esta regra mostra a mensagem do parâmetro msg. é caractere e que será mostrada •msgId: é uma string (sem espaços em branco nem aspas) que será utilizado somente se a transação é definida também como business component1. var ou expressão caractere. cond.

é que aqui é permitido continuar a execução. pois não está condicionada a um modo particular. não é permitido que seja modificada sua data. vemos que esta regra não nos serve.isEmpty(). FUNCIONALIDADE: A subtração é realizada levando em consideração o modo que se esteja trabalhando na transação (Insert. not). /*Regra definida na transação "Customer”*/ Se avalia a condição CustomerName. not) Evento/momento de disparo: é um dos eventos predefinidos pelo GeneXus disponíveis para regras de transações. cada vez que se ingressa uma linha com um produto que se está comprando. FUNCIONALIDADE: em uma transação. Noaccept OBJETIVO: Permite indicar que o atributo não aceite valores por parte do usuário (será somente de saída). o valor do atributo att1 . or. então contamos com a regra Noaccept.Update: subtrai o valor do atributo att2. cond: é uma expressão booleana (que pode conter os operadores lógicos and.EXEMPLO: Msg( ‘Nome do Cliente não foi informado’ ) if CustomerName. Se prestarmos atenção.isEmpty(). o valor do atributo att1 . 88 . or. razão pelo qual será disparada tanto quando estiver inserindo uma nova linha na fatura. att2: são atributos pertencentes a alguma das tabelas base associadas à transação. ONDE: att1. att2) [if cond]. Nestes últimos dois casos é incorreto disparar a regra. Update ou Delete). todos os atributos que pertencem as tabelas base associadas a transação. que permitem definir o momento específico de execução de uma regra. ONDE: att: é um atributo pertencente a alguma(s) da(s) tabela(s) base(s) associada(s) à transação cond: é uma expressão booleana (pode conter os operadores lógicos and. Subtract OBJETIVO: Subtrai o valor de um atributo ao valor de outro atributo. Se quisermos que um atributo destas características não seja aceito. ou a suas tabelas estendidas (e devem estar declarados na estrutura). A diferença que ocorre com a regra Error. SINTAXE: Noaccept(att) [if cond] [on evento/momento de disparo]. e se esta se satisfaz mostra-se a mensagem ‘Nome do Cliente não foi informado’.Delete: soma a valor de att2. SINTAXE: subtract(att1. /* Regra definida na transação “Invoice” */ Se está modificando uma fatura (modo Update). Em modo: . Isto poderia ser feito de forma simples com a seguinte regra de atribuição: ProductStock = ProductStock – InvoiceLineQuantity. a diferença entre o valor novo e o velho do att1 EXEMPLO: Na transação “Invoice”. pois não se trata de um erro e sim de uma advertência. se satisfaz a condição especificada. segundo a quantidade levada. como quando se está eliminando ou modificando uma já existente. por default são aceitos. todavia.Insert: subtrai o valor do atributo att2. EXEMPLO: Noaccept( InvoiceDate) if Update. se deve diminuir o stock do mesmo.

Delete). CustomerTotalPurchases = CustomerTotalPurchases – old(InvoiceTotal) + InvoiceTotal if Update. o valor do atributo att1 . se a condição especificada for satisfeita. subtrair ou somar. o valor do atributo att1 . ONDE: att1. “devolver” ao estoque o que havia sido quitado quando se inseriu a linha. ou seja. tendo que escrever as seguintes 3 regras de atribuição na transação “Invoice” : CustomerTotalPurchases = CustomerTotalPurchases + InvoiceTotal if Insert. ou a suas estendidas (e devem estar declarados na estrutura).Insert: soma ao valor do atributo att2. O comportamento desejado é que cada vez que for criado uma fatura para um cliente.InvoiceLineQuantity if Insert. 89 . ProductStock). para registrar o valor total de compras efetuadas pelo mesmo. CustomerTotalPurchases = CustomerTotalPurchases – InvoiceTotal if Delete. tendo em conta todos os casos possíveis seria ter 3 regras: ProductStock =ProductStock . por: subtract( InvoiceLineQuantity. para tanto é importante ter em conta o modo de trabalho na transação (Insert. att2 : são os atributos pertencentes a alguma das tabelas base associadas a transação. Update. Como vimos na regra subtract. dependendo do modo. dependendo do modo. a diferença entre o valor novo e o velho de att1 EXEMPLO: Definimos na transação "Customer". cond: é uma expressão booleana. att2) [if cond]. quando é eliminada uma linha existente. Add OBJETIVO: Soma o valor de um atributo ao valor de outro atributo.De fato. ProductStock=ProductStock + old(InvoiceLineQuantity) – InvoiceLineQuantity if Update. Aqui estamos utilizando a função “old”.Update: soma ao valor do atributo att2. que devolve o valor armazenado do atributo (é o valor antes de modificálo). Esta regra tem a inteligência para. O correto então. que encarrega de somar ou diminuir. seja somado o total da fatura (InvoiceTotal) ao total de compras efetuadas pelo cliente (CustomerTotalPurchases). Update ou Delete). FUNCIONALIDADE: a adição é realizada considerando o modo da transação (Insert. Ao invés disso o GeneXus nos brinda com a regra add. SINTAXE: add( att1. um atributo de nome CustomerTotalPurchases. Então podemos substituir as 3 atribuições anteriores. ProductStock =ProductStock + InvoiceLineQuantity if Delete.Delete: subtrai ao valor de att2. O GeneXus nos libera de termos que considerar os modos. não devemos esquecer que na transação “Invoice” podemos também eliminar e modificar Invoice. e não somente criá-las. a operação contrária deve ser realizada. Para evitar fazer tudo GeneXus fornece a regra subtract que se encarrega de fazer a atribuição correta de acordo ao modo. Modo: .

Desenha a transação "Invoice" contendo um Número de linha de Invoice (atributo InvoiceLineId) como identificador único do segundo nível. o valor do atributo InvoiceTotal • se modifica uma fatura (Update): soma ao valor do atributo CustomerTotalPurchases. e o valor resultante é atribuído tanto ao atributo att1 do novo registro. soma-se o valor step. att2 : deve pertencer a uma tabela diretamente superordinada à do atributo att1. como ao atributo att2 para conservar o último número atribuído. e se atribui o valor obtido tanto a att1 do registro que vai inserir. pois pertence a uma tabela diretamente superordinada). incrementa-se o valor do parâmetro step.não inferido). como a att2 pertencente a uma tabela diretamente superordinada com respeito à tabela que contem a att1. que deseja serializar (depende de estar declarado na estrutura). step: é o passo ou incremento da serialização FUNCIONALIDADE: o propósito desta regra é atribuir um número correlativo à att1 cada vez que é inserido um registro na tabela que pertence att1. CustomerTotalPurchases E na transação “Invoice” inferimos o atributo CustomerTotalPurchases – estendida -. step). E conseguimos o comportamento desejado. se acesse ao att2 (haverá um só valor deste atributo relacionado. o valor do atributo InvoiceTotal • se elimina uma fatura (Delete): subtrai ao valor do atributo CustomerTotalPurchases. A estrutura da transação seria: INVOICE { InvoiceId* CustomerId CustomerName InvoiceDate InvoiceLastLineId { INVOICEDETAIL InvoiceLineId* ProductId ProductDescription …… } } 90 . att2. SINTAXE: Serial( att1. step).. Quando um registro é inserido por meio de uma transação na qual foi definida a regra: Serial (att1. ONDE: att1 : é um atributo pertencente a alguma das tabelas base associadas à transação (isto é. Toma-se o valor de att2 att2 contém o último número utilizado na auto-numeração).Se agregarmos na transação "Customer“ o atributo CustomerTotalPurchases (total de compras do cliente): CustomerId* CustomerName CustomerAddress CustomerGender . att2. podemos definir a regra: add(InvoiceTotal. que é: • se insere uma fatura (Insert): soma ao valor do atributo CustomerTotalPurchases. a diferença entre o valor novo e o velho de InvoiceTotal que pertence a tabela Serial OBJETIVO: Permite serializar (auto-numerar) atributos numéricos.. CustomerTotalPurchases).

definindo a regra: Serial (InvoiceLineId. e por último o terceiro parâmetro é para indicar o incremento (neste caso se incrementa de um em um). Isto é. a qual é diretamente superordinada à tabela que contém o atributo à numerar (InvoiceLineId). A regra serial está implementada de forma que necessita deste atributo (para fixar o último número utilizado. números de clientes.). pode ser observado que InvoiceLastLineId encontra-se na tabela de chave InvoiceId*.Neste desenho o atributo ProductId unicamente. Consideração: A regra serial é útil na hora de auto-numerar (serializar) linhas. é possível ingressar o mesmo produto em distintas linhas. InvoiceLastLineId. 1). Pode ser útil atribuir por meio do sistema. números de faturas. não é o identificador único do nível. números correlativos ao campo InvoiceLineId. etc. no segundo parâmetro deve ser indicado um atributo cuja função é guardar o último valor atribuído até o momento. 91 . e sim a chave estrangeira Cada linha tem um número de linha que é identificada de forma única. A regra serial o requer assim. cada fatura terá no cabeçalho. não em cabeçalhos (por exemplo. Para utilizá-la precisa definir um atributo em uma tabela diretamente superordinada. um atributo que armazena o último número de linha atribuído até o momento (InvoiceLastLineId). e atribuir o próximo número da nova linha). isto resulta que se desejarmos auto-numerar linhas devemos incluir este atributo no nível da estrutura imediatamente superior ao do atributo a serializar. O segundo parâmetro (no exemplo InvoiceLastLineId) deve pertencer a uma tabela diretamente superordinada à tabela que contém o atributo que se deseja numerar automaticamente (InvoiceLineId). O primeiro parâmetro da regra serial define qual é o atributo a ser numerado automaticamente. somá-lo ou incremento. No exemplo.

selecionar o valor True. o valor Yes indica a este que não deve aplicar a propriedade em caso de que a tabela seja receptora de replicação (mas que deve manter os números vindos da replicação). Para maiores detalhes desta propriedade. Step: Mediante esta propriedade é possível configurar o incremento do campo (entre dois registros).Contamos com uma solução muito mais simples para autonumerar cabeçalhos: quando uma tabela tem uma chave simples (é formada por somente um atributo) e o tipo de dados é numérico. significa que será realizada a numeração automática do mesmo. pode numerar-se automaticamente utilizando a funcionalidade que fornecem os administradores de base de dados para isto. For replication: Esta propriedade é somente válida para o motor de base de dados SQL Server. 92 . recomendamos acessar ao Help de GeneXus. Serão agregadas as seguintes propriedades no diálogo: Start: Mediante esta propriedade se configura a partir de qual número começa a numeração automática. A forma de indicá-lo em GeneXus é configurando a propriedade Autonumber do atributo chave: Se na propriedade Autonumber de um atributo numérico chave.

FUNCIONALIDADE: Em uma transação.Update OBJETIVO: Possibilita atualizar no form de uma transação (Win/Web) atributos da tabela estendida (inferidos). e portanto não aceitos. todos os atributos que pertencem as tabelas associadas a transação. são inferidos. EXEMPLO: InvoiceId* InvoiceDate CustomerId CustomerName … CustomerId* CustomerName … update(CustomerName). não pertencem a base. para que o usuário possa modificar a partir do form seu valor. então temos a regra Update. por default são aceitos e os que pertencem a tabela estendida. ONDE: atti: é um atributo pertencente a tabela estendida de alguma das tabelas bases associadas a transação. atti …]). 93 . Mas se queremos que estes atributos inferidos sejam aceitos. SINTAXE: Update( att1[.

GeneXus entende que a regra está associada ao último dos níveis dos atributos envolvidos. e é um atributo do primeiro nível da transação. GeneXus determina que se trata de uma regra associada ao primeiro nível. se uma regra referencia unicamente a atributos do primeiro nível da transação na qual se encontra definida (seja na própria regra ou na condição de disparo). Em seguida apresentaremos exemplos concretos: 1) Se define a seguinte regra na transação “Invoice”: Default(InvoiceDate. GeneXus determina que se trata de uma regra associada ao segundo nível. já que será no último nível que terá os valores de todos os atributos implicados.Regras Conceitos importantes • Em qual nível de uma transação são executadas as regras definidas na mesma? • Como condicionar regras para que sejam executadas em determinados modos? Em qual nível de uma transação são executadas as regras definidas na mesma? Na maioria das vezes não é necessário agregar explicitamente na definição das regras o nível da transação no qual se deseja que sejam disparadas. &today). ProductStock ). Por exemplo. 2) Se definir a seguinte regra na transação “Invoice”: subtract( InvoiceLineQuantity. como o único atributo que se menciona na regra é InvoiceDate. como os dois atributos mencionados na mesma se encontram no segundo nível da transação. se uma regra referencia somente atributos do segundo nível da transação na qual está definida (seja na própria regra ou na condição de disparo). Analogamente. GeneXus entende que a mesma estará associada ao primeiro nível da transação. já que os atributos envolvidos nas regras guiam GeneXus ao nível correspondente para executá-las. No caso que uma regra referencie atributos de vários níveis. GeneXus entende que a mesma estará associada ao segundo nível da transação. 94 .

para cada fatura com a qual se trabalhe através da transação “Invoice”: . Quando nos referimos que uma regra está associada a determinado nível. a regra: InvoiceLineDiscount = InvoiceLineAmount * CustomerDiscountPercentage/100 é uma regra associada ao segundo nível da transação “Invoice”. 95 . ProductStock) é uma regra associada ao segundo nível da transação “Invoice”. Por exemplo. portanto. a regra subtract(InvoiceLineQuantity.3) Se definir a seguinte regra na transação “Invoice”: InvoiceLineDiscount= InvoiceLineAmount * CustomerDiscountPercentage/100. Concluindo. se por exemplo uma regra se executa por default para o primeiro nível de uma transação e se deseja que se execute para o segundo. por default esta regra está associada ao primeiro nível da transação. No caso do terceiro exemplo. Isto é. Se por algum motivo desejamos que a regra se execute para cada uma das instancias correspondentes as linhas em vez de executar-se para a instancia correspondente ao cabeçalho. De modo que esta regra se executa para toda linha da fatura que se insira. e não para a instancia correspondente ao cabeçalho como era o comportamento por default. sendo InvoiceLineDiscount (desconto correspondente a uma linha) um atributo pertencente ao segundo nível da transação “Invoice” e CustomerDiscountPercentage (porcentagem de desconto ortogado a um cliente) um atributo declarado no primeiro nível da transação “Invoice”. Por exemplo. significa que a mesma se executa para cada instancia com a qual se trabalhe através desse nível (se cumprir com a condição de disparo da regra). já que o único atributo referenciado na regra se encontra no primeiro nível da transação. &today) é uma regra associada ao primeiro nível da transação “Invoice”. o nível associado por default a regra será o primeiro. Qual nível de disparo por default é associado uma regra que não referencia atributos? Quando não tem atributos envolvidos numa regra. Quando tem que especificar explicitamente o nível de disparo de uma regra? Existe uma cláusula opcional de nome Level que permite modificar o nível por default de disparo de uma regra. a seguinte regra definida na transação “Invoice”: Error(‘Faturas não podem ser eliminadas’) if Delete. se definimos a seguinte regra na transação “Invoice”: msg(‘A data da fatura é maior que a data atual’) if InvoiceDate > &Today. a cláusula Level seguida de um ou vários atributos do segundo nível: msg(‘A data da fatura é maior que a data atual’) if InvoiceDate>&Today Level InvoiceLineAmount. E somente em alguns casos que assim o requeiram. atualize ou elimine através do segundo nível da transação “Invoice”. a mesma regra voltará a ser disparada mais adiante. o nível associado por default a regra será o primeiro. se deverá agregar a regra ou componente Level seguido de um atributo ou conjunto de atributos do segundo nível.para o cabeçalho: são executadas as regras associadas ao primeiro nível . Isto fará que a regra se execute para cada uma das instancias correspondentes as linhas. alterando-o por um nível posterior. a regra Default(InvoiceDate. naquele momento que tenha todos os dados necessários. isto é. Isto significa que executando toda linha da fatura que se insira.para cada uma das linhas: são executadas as regras associadas ao segundo nível É importante saber que como norma geral GeneXus sempre determina que uma regra seja disparada no primeiro momento possível. GeneXus determina que se trata de uma regra associada ao segundo nível da transação. não tem atributos envolvidos. atualize ou elimine através do segundo nível da transação “Invoice”. Isto significa que ao executar todo cabeçalho de fatura inserido através do primeiro nível da transação “Invoice” (a regra Default tem a particularidade de se disparar unicamente quando o modo de execução é Insert). teremos que agregar na definição da regra. No caso do primeiro exemplo visto. No caso do segundo exemplo visto.

o atributo InvoiceDate fica desabilitado em todos os modos de execução. É fácil compreender que o atributo InvoiceDate já guia GeneXus que se trata de uma regra associada ao primeiro nível. 96 . No seguinte exemplo. o fato de ter agregado a cláusula Level a regra não agrega mais informação visto que o atributo que já tem essa informação na definição da própria regra: msg(‘A data da fatura é maior que a data atual’) if InvoiceDate > &Today Level CustomerId. a um nível posterior. não contribuindo com informação útil da cláusula Level neste exemplo. a cláusula Level somente faz sentido que seja agregada para modificar o nível por default de disparo de uma regra. Se a regra foi definida sem condição de disparo que temos explicitado. a mesma se execute no primeiro nível. Como condicionar regras para que se executem em determinados modos? GeneXus fornece as seguintes funções booleanas para poder incluí-las na condição de disparo das regras com o objetivo de limitá-las que se executem pontualmente em alguns dos modos possíveis: • • • Insert Update Delete Exemplos de uso (todas as regras correspondem a transação “Invoice”) 1) Noaccept( InvoiceDate ) if Update. não é possível que possuindo atributos envolvidos de um segundo nível em uma regra. Concluindo. para indicar que se deseja que a mesma esteja associada ao segundo nível da transação. já que no primeiro nível não tem informação do ou dos níveis inferiores (além de que tem N instancias para os níveis inferiores). se dispara o error impedindo a eliminação. não se permite que sua data seja modificada. se incluiu a cláusula Level na definição da regra.Agregar a cláusula Level a uma regra somente faz sentido se a continuação da mesma são mencionados atributos que são de algum nível posterior aos níveis dos atributos implicados na definição da regra em si. se dispara o error impedindo a eliminação. 3) Error( ‘Linhas da Faturas não podem ser eliminadas’ ) if Delete Level InvoiceLineQuantity. Se tentar eliminar uma fatura. a cláusula Level definida não contribuiu com informação útil neste caso. Isto é. Como não tem atributos envolvidos na regra. por default o nível associado a regra será o primeiro. Se está modificando uma fatura (modo Update). Por último. Se tenta eliminar uma linha de uma fatura. como o atributo que segue a cláusula é de um nível superior ao nível dos atributos referenciados na regra. assim que o especificado pela cláusula Level no exemplo não contribui mais informação e portanto é desnecessário. no exemplo que segue: InvoiceLineDiscount= InvoiceLineAmount * CustomerDiscountPercentage/100 Level InvoiceDate. 2) Error( ‘Faturas não podem ser eliminadas’ ) if Delete. Observar que se tem explícito na regra a cláusula Level seguida de um atributo do segundo nível da transação “Invoice”. De modo que a regra seguirá estando associada ao segundo nível da transação “Invoice”.

Fórmulas 97 .

98 .Locais: Entre certo código Veremos este conceito mais adiante com mais conhecimento GeneXus Veremos este conceito em primeiro lugar Quando definirmos uma fórmula. GeneXus pode combinar a consulta / cálculo associada a fórmula com a consulta na qual a fórmula está presente e assim gerar sentenças otimizadas.Globais: A nível da Base de Conhecimento .Fórmulas Objetivos e Definição • Definir fórmulas possibilita compartilhar conhecimento e obter código gerado otimizado • Quando o valor de um atributo ou variável pode ser calculado a partir de outros atributos. constantes e/ou funções. pode ser definida como uma fórmula • Contamos com 2 formas de definir fórmulas: .

Fórmulas Globais • Fórmula Global = atributo onde o analista GeneXus atribui um cálculo associado • Somente atributos podem ser definidos como fórmulas globais. variáveis não podem • Como é a realizada a definição? Acessando o editor de fórmulas a partir da estrutura da transação 99 .

100 .Fórmulas Globais • Dizemos que: atributos fórmulas globais = atributos virtuais • Significando que: . Todavia.Para cada objeto que referencie um atributo fórmula global.Tabela na qual o atributo seria armazenado se não fosse fórmula Como explicamos neste slide. não são criados como campos físico em tabelas. para conhecer o contexto na qual foi definida. os atributos definidos como fórmula global.Não são criados como atributos físicos . dizemos que são atributos virtuais. dizemos que tem uma tabela “associada” ou tabela “base”. e contar com esse contexto do momento de disparar o cálculo correspondente onde for referenciado. GeneXus incluirá em seu programa gerado o código necessário para realizar o cálculo e mostrá-lo em tempo de execução • Tabela base / Tabela associada a um atributo fórmula global: .

Count.Quando definirmos fórmulas no GeneXus não indicamos a classificação . Max.A classificação é externa ao GeneXus e sua finalidade é agrupar fórmulas por: Tipo de cálculo oferecido Atributos que podem ser envolvidos na sua definição 101 . Find • Compostas: Conjunto de expressões Horizontais e/ou Aggregate TODAS PERMITEM INCLUIR CONDIÇÃO DE DISPARO PODE SER GLOBAIS E LOCAIS • Importante: . Average.Fórmulas Classificação • Horizontais: Uma ou várias expressões aritméticas • Aggregate: Sum. Min.

é possível envolver atributos pertencentes a tabela associada ao atributo que a fórmula está sendo definida e a sua tabela estendida. ao definir que o atributo CustomerBalance é fórmula. já que se fosse armazenar dito atributo novamente (seja porque o analista definiu que deixa de ser fórmula ou que é fórmula redundante) seria criado como atributo físico na tabela CUSTOMER. o mesmo deixará de existir como campo físico da tabela CUSTOMER. 102 . O tipo de cálculo desta fórmula definida é horizontal. portanto os atributos que podem ser referenciado na definição desta fórmula são os pertencentes a tabela CUSTOMER (tanto os armazenados como fórmulas) e sua tabela estendida. Diremos a partir desse momento CustomerBalance é um atributo virtual e que sua tabela “base ou associada” será CUSTOMER. No exemplo. já que consiste em uma expressão aritmética.Fórmulas Classificação • Exemplo de Fórmula Horizontal (Global) : Customer { CustomerId* CustomerName CustomerTotalPurchases CustomerTotalPayments CustomerBalance } CustomerTotalPurchases – CustomerTotalPayments DEIXA DE PERTENCER FISICAMENTE A TABELA TABELA CUSTOMER CustomerId* CustomerName CustomerTotalPurchases CustomerTotalPayments Na definição de um atributo como fórmula horizontal.

103 . Neste exemplo o atributo InvoiceDetailAmount foi definido como fórmula global também. será criado em dita tabela física. foi associado um cálculo a este atributo e o mesmo passará a ser um atributo virtual. ProductPrice*InvoiceDetailQuantity*0. utilizando o editor de fórmulas. já que consiste em 2 expressões aritméticas condicionais. Como podemos observar a fórmula definida cai na classificação de horizontal. Isto é.9 otherwise. A tabela associada ao atributo InvoiceDetailAmount será INVOICEDETAIL.Fórmulas Classificação • Exemplo II de Fórmula Horizontal (Global) : Invoice { InvoiceId* CustomerId CustomerName InvoiceDate Detail { InvoiceDetailId* ProductId ProductDescription ProductPrice InvoiceDetailQuantity InvoiceDetailAmount } } ProductPrice*InvoiceDetailQuantity if InvoiceDetailQuantity<=100. Os atributos envolvidos na definição da fórmula pertencem a tabela INVOICEDETAIL ou a sua tabela estendida. caso dito atributo for armazenado novamente.

que GeneXus conta e soma as linhas relacionadas a seus cabeçalhos (ao somar e contar. a tabela a ser navegada em ambas fórmulas Aggregate é INVOICEDETAIL. um error será mostrado na listagem de navegação correspondente. Os atributos que poderemos referenciar na definição de uma fórmula Aggregate deverão pertencer a tabela a ser navegada e sua tabela estendida + a tabela associada ao atributo que está sendo definido como fórmula e sua tabela estendida.InvoiceId } } No exemplo os atributos InvoiceDetail e InvoiceAmount foram definidos como fórmulas globais.InvoiceId = INVOICE. pelos atributos envolvidos na definição da fórmula. Por último. já que utilizando o editor de fórmulas foi definido uma fórmula para cada um destes atributos (os passando a ser atributos virtuais). Em nosso exemplo. já que tanto na definição de Sum como Count. já temos conhecimento de qual tabela pretendemos navegar para efetuar o cálculo. A tabela a ser navegada numa fórmula Aggregate. Quando definirmos uma fórmula Aggregate. em ambos casos se trata de fórmulas Aggregate. aplica automaticamente o filtro INVOICEDETAIL. já que caso estes atributos estivesses armazenados.InvoiceId ). seriam criados em dita tabela física. um filtro automático por igualdade pelos atributos com o mesmo nome). Visto que as fórmulas definidas são Count e Sum respectivamente. GeneXus aplicará essa relação (isto é. 104 . mas também envolvem uma tabela a ser navegada.InvoiceId = INVOICE. Isto é o que acontece neste 2 exemplos. A tabela associada a ambos atributos fórmula é INVOICE. GeneXus inferi qual a tabela a ser navegada por uma fórmula Aggregate. As fórmulas Aggregate não possuem somente uma tabela base associada (como todas as fórmulas). é a tabela que será navegada para realizar o cálculo. De envolver numa fórmula Aggregate atributos que não pertençam a este contexto mencionado.Fórmulas Classificação • Exemplos de Fórmulas Aggregate (Globais) : Invoice { InvoiceId* CustomerId CustomerName InvoiceDate InvoiceDetail Count(InvoiceDetailQuantity) InvoiceAmount Sum(InvoiceDetailAmount) Detail { InvoiceDetailId* ProductId ProductDescription ProductPrice Em ambos os cálculos somente intervém os registros que InvoiceDetailQuantity cumprirem: InvoiceDetailAmount INVOICEDETAIL. havendo atributos em comum (com o mesmo nome) nas tabelas envolvidas na definição de uma fórmula. temos referenciado a um único atributo associado a INVOICEDETAIL.

GeneXus levará ambas em consideração: implícitas + explícitas. Pode referenciar qualquer atributo da tabela na qual se quer contar registros (que cumpram com condições explícitas e/ou implícitas). conta ou média/ Também poderíamos ter definido condições de filtro explícitas e no caso de fazê-las. Também dita expressão poderia envolver constantes e/ou funções. [Condição Explícita. Nos 2 exemplos de fórmulas Sum e Count que vimos. a expressão a ser somada o contada (que num caso consistiu num atributo armazenado e no outro caso num atributo fórmula). somente definimos o parâmetro obrigatório. estas também permitem incluir condição de disparo. ou média. somar. o primeiro parâmetro deve corresponder a um atributo e não a uma expressão. 105 . Por último. Count.Sintaxe completa de Sum. vale mencionar uma exceção e é em particular nas fórmulas Count. Valor por Default]) [if Condição Disparo]. Da mesma forma que todas as fórmulas. Vimos que GeneXus determina condições de filtro implícitas ao realizar ao soma. De forma opcional é possível definir um valor por default a ser retornado quando não são encontrados registros para contar. Average: Sum | Count | Average(Expressão.

Portanto um produto numa linha de uma fatura. representamos que cada produto tem uma lista de preços de acordo com uma data de alteração dos mesmos. são os que pertencem a tabela estendida da tabela base associada ao nível em questão. Por que? Porque o novo desenho estará representando que um produto não vai ter um preço único. Neste exemplo. o atributo ProductPriceListPrice não poderá estar presente no segundo nível da transação Invoice. Lembre que os atributos que podem ser inferidos em determinado nível de uma transação. 106 . Ao efetuar esta mudança. considerando a data da fatura. não inclui a tabela PRODUCTPRICELIST (naquela que o atributo esteja ProductPriceListPrice): portanto no nível Detail da transação Invoice (associado a tabela INVOICEDETAIL) não é possível inferir o atributo ProductPriceListPrice (armazenado na tabela PRODUCTPRICELIST). InvoiceDetailAmount 0. ProductPriceListPrice) } } InvoiceDetailProductPrice*InvoiceDetailQuantity Modificamos o desenho das transações para que ao invés de representar que cada produto possui um preço único. mas sim muitos: um para cada data da alteração do preço do mesmo.Fórmulas Classificação • Exemplos de Fórmulas Aggregate (Globais) : Invoice Product { { InvoiceId* ProductId* CustomerId ProductDescription CustomerName PriceList InvoiceDate { InvoiceDetail Count(InvoiceDetailQuantity) ProductPriceListDate* InvoiceAmount Sum(InvoiceDetailAmount) ProductPriceListPrice Detail } { } InvoiceDetailId* ProductId ProductDescription InvoiceDetailQuantity Max(ProductPriceListDate. a tabela estendida da tabela INVOICEDETAIL. teremos que “buscar” o preço vigente do mesmo. InvoiceDetailProductPrice ProductPriceListDate<=InvoiceDate.

de todos os preços que tenham data menor ou igual a data da fatura. se retorna este atributo GeneXus infere a tabela a ser navegada pelo último parâmetro da fórmula (o atributo de retorno). [Condição explícita]. com uma única diferença de que ao encontrar um conjunto de registros que cumpram com as condições. um error é mostrado na listagem de navegaçã correspondente. um novo atributo de nome InvoiceDetailProductPrice. Como resultado é um modelo de dados não normalizado. e mostrará o error ao querer reorganizar a base de dados. também permite buscar um registro que cumpra com certas condições. então GeneXus não terá outra opção que armazená-lo na tabela INVOICEDETAIL e este atributo secundário já estará em outra tabela (PRODUCTPRICELIST). A fórmula Find por sua vez. queremos aquele que tenha data maior. 107 . contudo se ter mais de 1 registro que cumpra com elas. ao qual o definiremos como fórmula global e portanto será um atributo virtual. A sintaxe Find é: Find (Expressão de retorno. será selecionado aquele registro que tenha valor mínimo para o atributo indicado no primeiro parâmetro e retorne o valor de retorno indicado no último parâmetro. ProductPriceListDate<= InvoiceDate. A dito atributo vamos associar a fórmula Max: Condições que devem cumprir os registros para ser considerados Valor de retorno se não encontrar nenhum registro que cumpra con las condições Max(ProductPriceListDate. ProductPriceListPrice) Atributo a maximixar entre os registros que cumpram as condições Para o registro encontrado. 0. os atributos que poderemos referenciar na definição de uma fórmula Aggregate deverão pertencer a tabela a ser navegada e sua tabela estendida + a tabela associada ao atributo definido como fórmula e sua tabela estendida. E como fazemos para mostrar em cada linha da factura. o preço vigente do produto da mesma? De todos os preços correspondentes ao produto de una linha. a fórmula devolverá o atributo de retorno correspondente ao primeiro registro encontrado (sem maximizar nem minimizar um valor no conjunto de registros que cumpram com as condições). Envolvendo atributos que não pertençam neste contexto mencionado.O que ocorre se deixarmos o atributo ProductPriceListPrice no nível Detail transação Invoice? Como não pode ser inferido. GeneXus considera o momento de efetuar a busca a condição explícita de filtro + as condições implícitas detectadas. A fórmula Min é totalmente análoga a Max. qual queremos recuperar? Evidentemente. Como já se foi explicado. [Valor por default) [if Condição de disparo] Observar que a expressão de retorno neste caso se escreve no primeiro parâmetro da fórmula. Procedemos então a criar no nível Detail da transação Invoice.

Fórmulas Classificação • Exemplo de Fórmula Composta (Global): Customer { CustomerId* CustomerName CustomerTotalPurchases CustomerTotalPayments CustomerBalance CustomerAverage } Sum(InvoiceAmount) / Count(InvoiceAmount) 108 .

Comunicação entre objetos 109 .

O esquema apresentado acima ilustra as possíveis interações entre objetos GeneXus para uma aplicação Web. Um objeto GeneXus pode chamar ou ser chamado por qualquer outro objeto. 110 . Observe que a flecha simples entre Web Panel e Procedimento PDF (assim como entre Transação e Procedimento PDF) indica que uma web panel poderá chamar um Procedimento PDF mas um Procedimento PDF não poderá chamar uma web panel (ou transação Web). e como especificar os parâmetros (no objeto chamador e no chamado) para a troca da informação. Veremos em seguida como chamar desde um objeto a outro. trocando informações através de parâmetros.Comunicação entre objetos Data Provider Procedimento Web Panel Transação Procedimento PDF Os objetos GeneXus podem comunicar-se entre eles ou com outros programas externos.

Comunicação entre objetos 2 possibilidades: 1) PgmName. par ) 1 N Parm(par1 . e com a particularidade de que o programa chamado retornará necessariamente ao menos um valor ao programa que chamou. etc. ….. parN) /* Chamada a PgmName*/ Parm(par1. parN). parN . …. A continuação daremos mais detalhes sobre o uso de CALL. …. procedimento. porque a UDP é utiliza unicamente para chamar Procedimentos e Data Providers (devido que estes cumprem com a condição de executar e devolver o controle ao chamador). deve ter declarada a lista de parâmetros que recebe. 111 . Quando na sintaxe da chamada se escreve o nome do objeto chamado e nenhum método de chamada. parsaída). parN) PARM – Quando um objeto é chamado desde outro com parâmetros. Uma chamada (seja com CALL ou UDP) pode ser utilizado em distintas partes do objeto chamador.Udp(par1. /*Declaração de parâmetros no objeto chamado*/ CALL . dependendo se o mesmo é uma transação. um objeto com interface uma vez chamado não devolve o controle ao chamador.Call(par . UDP e PARM.Permite chamar a um objeto GeneXus ou a um programa externo. Esta declaração se realiza mediante a regra: PARM. wep panel. e pode ser omitida e escrever diretamente: att|&var = PgmName( par1. UDP (User Defined Procedure)– Permite chamar a um objeto GeneXus ou programa externo tanto passando parâmetros ou não. Quer dizer que se define que certo atributo é uma formula e que a definição da mesma consiste no chamada a um procedimento utilizando UDP.. podendo passar parâmetros ou não. A UDP pode utilizar-se também na definição de um atributo formula. Em ambientes Web. /*Chamada a PgmName*/ /*Declaração de parâmetros no objeto chamado*/ Pode omitir-se 2) att|&var = PgmName. .. …. se assume que se está chamando com udp.

Agora observemos na sintaxe da chamada ao procedimento. • em algum lugar do objeto chamado deverá ser atribuído valor ao parâmetro de retorno.Call(InvoiceId) E nas regras do procedimento ListInvoice: Parm(InvoiceId) 2) Ex: &discount = GetDiscount. Podemos ver então que quando se utiliza CALL para chamar um objeto enviando-lhe Nparâmetros. 112 . &disc). aqui mostraremos que CALL permite chamar um objeto com estilo de chamada a um programa. estas chamadas poderão escrever-se em uma seção ou outra do mesmo. No segundo exemplo é utilizado UDP para chamar um procedimento (objeto GetDiscount) passando dois parâmetros (ProductId. mas independentemente disso.udp(ProductId. Por este motivo no procedimento solicitado são declarados três parâmetros utilizando a regra parm: os dois parâmetros recebidos + o parâmetro de retorno no último lugar. Aqui mostramos um exemplo do uso do CALL para realizar uma chamada e outro exemplo do uso do UDP. que o mesmo retornará um valor (na variável &disc). caso que veremos mais adiante): • na regra parm do objeto chamado se devem declarar N + 1 • o último parâmetro declarado na regra parm do objeto chamado corresponde ao que se encontra no começo de tudo na chamada. Dependendo de qual objeto for o chamador. mediante a regra parm).Comunicação entre objetos 2 possibilidades – Exemplos: 1) A partir da transação Invoice chamamos um procedimento PDF para imprimir a fatura: ListInvoice. é dizer. CustomerId). No primeiro exemplo esta se utilizando CALL para chamar um procedimento pdf (objeto ListInvoice) passando um parâmetro (InvoiceId). No procedimento chamado se declarou o parâmetro que recebe (em sua seção de regras. se devem declarar os N parâmetros (posicionais e do mesmo tipo de dados que os enviados) no objeto solicitado mediante a regra parm.CustomerId . Por outro lado quando se utiliza UDP para chamar um objeto enviando N parâmetros (exceto que seja o caso particular de um Data Provider. ao que recebe o valor retornado. enquanto que UDP uma chamada a um objeto com estilo de chamada em uma função.CustomerId) Na proc GetDiscount Parm(ProductId.

como bandeira (flag). independentemente de como tenha sido enviado. terá que enviar o mesmo. >=. maior ou igual. menor ou igual. assim como a outros objetos. por maior. o programador GeneXus deverá decidir para cada parâmetro. poderemos terminar de compreender melhor este tema. e se estiver numa variável. 113 . em um atributo. Todavia. não sendo possível modificar o valor recebido. LIKE. se tivermos que enviar dados por parâmetro ao objeto chamado. Se for declarar um atributo. etc. poderá utilizar livremente a mesma lógica do objeto chamado: pode utilizá-la como condição de filtro por igualdade. Quando cheguemos à etapa do curso na qual podemos chamar a procedimentos pdf para listagem. • Atributo: Automaticamente o mesmo atuará como filtro por igualdade no objeto. precisamos determinar se enviaremos atributos e/ou variáveis: se um dado a ser enviado por parâmetro. etc. ou para o que se queira. terá que enviar a variável. automaticamente o mesmo atuará como filtro por igualdade no objeto. <=. Qual é a diferença entre declarar o parâmetro como variável ou como atributo na regra parm do objeto chamado? Se for declarar como uma variável. ao declarar a lista de parâmetros no objeto chamado. na lógica do objeto chamado: • como condição de filtro por =. Ao definir uma Chamada a um objeto (seja utilizando CALL ou UDP). poderá utilizar para alguma operação aritmética. • etc. passando parâmetros. se encontra no objeto que o chamou. se o declara como um atributo ou uma variável. LIKE. menor. <. >. • para alguma operação aritmética.Declarar o que na regra parm: variável ou atributo? • Variável: Pode ser utilizada livremente.. • como flag (bandeira). não sendo possível modificar o valor recebido.

isto é. e se for outro parâmetro diferente do último. será de entrada-saída. como é o caso do terceiro parâmetro do exemplo. in:&par2. os parâmetros somente podem ser passados por valor. se devolve ao objeto que o chamou o valor que tenha ficado (out). • se o objeto foi chamado com UDP. isto tem como conseqüência que serão enviados mais bytes do que os necessários. . que pode redundar em um overhead importante. 3. ou seja. a utilização de parâmetros de tipo out têm a vantagem de que não é necessário enviar parâmetro na chamada. isto se refere que para a maioria das linguagens é mais eficiente passar os parâmetros por referência (inout) que por valor (in / out). inout) • Para cada parâmetro declarado na regra parm. 114 . para poder obter esta funcionalidade de passálos por referência é necessário que exista conversões de parâmetros. Otimizar a passagem de parâmetros de acordo com a arquitetura gerada (sendo uma vantagem que contrasta com a anterior). por exemplo. inout:&par4). será de saída.Definição de tipo de passagem de parâmetros (in. Melhor especificação da semântica das interfaces. o que é inconveniente especialmente nos casos como Internet. Como pode-se perceber claramente na sintaxe do exemplo o primeiro parâmetro definido é de saída. mas em Java. o parâmetro. • Independência da linguagem de geração. 2.se o mesmo não chegar com valor e depois da execução do objeto que o chamado. por outro lado. • Otimizar a passagem de parâmetros das aplicações de acordo com a arquitetura implementada (vantagem que contrasta com a anterior). diferente de definir os parâmetros inout (tem que passar todos parâmetros). dependerá do seguinte: • se o objeto foi chamado com CALL. quando se trata de aplicações distribuídas (por exemplo Java com RMI ou HTTP). ao gerar as aplicações utilizando diferentes linguagens de geração não muda o comportamento dos parâmetros baseados ao comportamento por default da linguagem de geração correspondente. possui as seguintes vantagens: 1. . Quando não for especificado. Independência da linguagem de geração.se o mesmo chegar com valor e depois da execução do objeto chamado.se o mesmo chegar com valor e depois da execução do objeto chamado. out. e o quarto parâmetro é de entrada-saída. o segundo parâmetro é de entrada. Declarar explicitamente como se quer que cada parâmetro opere. e se trata do último parâmetro. &par3. fica claro: . não devolve ao objeto que o chamou o valor que tenha ficado (in). é devolvido ao objeto que o chamou o valor que tenha ficado (inout). • Vantagens: • Melhor especificação da semântica das interfaces. é possível definir que o mesmo seja: − de entrada (in) − de saída (out) − de entrada-saída (inout) • Exemplo: parm( out:&par1. se define explicitamente como deseja que cada parâmetro opere. dependerá da linguagem de operação. o GeneXus e o programador quando trabalham com um objeto.

Link = PgmName.artech. são declarados com a regra parm 2) control.com.Link([. transação.Link = Link(URL) Ex: imagem. PgmName (o objeto chamado) poderá ser uma web panel. mas não aprofundaremos sobre este conceito neste curso 115 .Link = Link(‘http://www. ____________________________________________________________________ 1 também um procedimento HTTP.par1 ….Link = Customer. ou procedimento PDF1.Link() Os parâmetros são opcionais e no caso de existirem.uy’) A função Link se associa à propriedade link de um controle dentro de qualquer evento de uma transação ou web panel.Comunicação entre objetos Web Mais possibilidades para definir chamadas Função Link 1) control. parN]) Ex: imagem. tendo como resultado que ao fazer click sobre dito controle se realiza a chamada ao objeto URL referenciada no Link.

ao chegar a sentença com o comando Link.par1 ….Comunicação entre objetos Web Mais possibilidades para definir chamadas Comando Link 1) PgmName. No caso de utilizar-se o comando Link como no exemplo 1. se redirecionará em forma automática à URL especificada.Link([. será equivalente à utilização do Call. Opcionalmente se poderá passar parâmetros ao objeto chamado.google.Link(CustomerId) 2) Link(URL) Ex: Link(‘http://www. chamando um PgmName (sendo PgmName uma web panel.com’) O comando Link pode ser utilizado dentro de qualquer evento de uma transação ou web panel¹ Quando se execute o evento. mas não aprofundaremos sobre este conceito neste curso 116 . transação ou procedimento PDF). ___________________________________________________________________ 1 também um procedimento HTTP. devendo declarar-se os mesmos no objeto chamado. parN]) Ex: Customer. com a regra parm.

Ordem de execução de regras e fórmulas .

Em nenhum momento. as seguintes 5 transações: “Customer” (para registrar os clientes da empresa) “Category” (as que pertencem cada cliente) “Shipping” (envios: guarda um histórico de custos de envio) “Invoice” (faturas emitidas aos clientes) “Product” (produtos que são vendidos pela empresa) Ressaltamos a estrutura da transação “Invoice”. Error( ‘Insufficient Stock’ ) if ProductStock<0. Quando for gerar.ShippingCharge) InvoiceSubTotal = SUM( InvoiceDetailAmount ) InvoiceTotal = InvoiceSubTotal – InvoiceDiscount + InvoiceShippingCharge {ProductId* ProductPrice ProductStock InvoiceDetailQuantity InvoiceDetailAmount} = InvoiceDetailQuantity * ProductPrice “Customer” CustomerId* CustomerName CategoryId CustomerTotalPurchases “Category” CategoryId* CategoryDiscount “Shipping” ShippingDate* ShippingCharge “Product” ProductId* ProductPrice ProducStock Regras: Add( InvoiceTotal. ShippingDate <=InvoiceDate. podemos optar pela alternativa de definir atributos fórmulas. Vamos supor que estamos definindo uma aplicação para uma empresa que vende determinados produtos. CustomerTotalPurchases).Ordem de execução de regras e fórmulas Transação "Invoice" InvoiceId* InvoiceDate CustomerId CustomerTotalPurchases CategoryDiscount InvoiceDiscount = InvoiceSubTotal *CategoryDiscount InvoiceShippingCharge = Max( ShippingDate. E definimos entre outras.. A forma de programar o comportamento das transações é definindo regras. o GeneXus determina as dependências existentes entre as regras e fórmulas definidas. o programador GeneXus especifica a seqüência de execução das regras e fórmulas definidas em uma transação. Quando temos cálculos para efetuar. ProductStock). escritas de forma declarativa. com seus atributos fórmulas e suas regras declaradas. e que conta com um serviço de entrega a domicílio que leva a mercadoria a seus clientes. Em que ordens serão disparadas as regras e fórmulas da transação “Invoice”? . Subtract( InvoiceDetailQuantity.

Por exemplo. se executam todas as regras e fórmulas que dependem desse atributo (e que na árvore se encontram para cima). ProductStock). Error( ‘Insuffcient Stock’) if ProductStock < 0 . por alterar o total. . as regras e fórmulas que se definem numa transação estão inter-relacionadas e GeneXus determina as dependências entre elas assim como sua ordem de avaliação. Error(‘Insufficient Stock’) if ProductStock < 0. já que depende do subtotal. por modificar esta regra o valor do atributo ProductStock verifica a necessidade de disparar a regra Error(‘Insufficient Stock’’) if ProductStock < 0. Podemos imaginar que a árvore é executada de baixo para cima. Subtract(InvoiceDetailQuantity.ShippingCharge) F. Além de serem disparadas todas as fórmulas e regras envolvidas na parte direita da Árvore desde o atributo InvoiceDetailQuantity. o GeneXus determinará as dependências existentes entre as regras e fórmulas definidas. e em conseqüência. Concluindo. F. também são disparadas as fórmulas e regras envolvidas na parte esquerda. Add(InvoiceTotal. InvoiceSubTotal = SUM( InvoiceDetailAmount ) F.Árvore de avaliação R. InvoiceDiscount = InvoiceSubTotal*CategoryDiscount F. Por último. CustomerTotalPurchases)..InvoiceDiscount + InvoiceShippingCharge F. e construirá logicamente uma árvore de dependências (ou árvore de avaliação) que determinará a seqüência de avaliação. esta fórmula será disparada novamente. Ou seja. cada vez que alteramos algum valor de um atributo. Deverá ser disparada novamente a fórmula correspondente ao total da fatura (InvoiceTotal) já que depende tanto do valor de InvoiceSubTotal como do valor de InvoiceDiscount. Para alterar o valor de uma linha. será disparada novamente também a regra Subtract(InvoiceDetailQuantity. alterando a quantidade de uma linha de uma fatura (InvoiceDetailQuantity). InvoiceTotal = InvoiceSubTotal . ProductStock) . InvoiceShippingCharge = MAX( ShippingDate. ShippingDate <= InvoiceDate. R. ao alterar o valor do atributo InvoiceDetailQuantity. a fórmula é disparada novamente correspondendo ao subtotal da fatura (InvoiceSubTotal) e como conseqüência. CustomerTotalPurchases). também será disparada a regra Add(InvoiceTotal. CustomerTotalPurchases InvoiceTotal InvoiceDiscount InvoiceShippingCharge error (‘Insufficient Stock ’) InvoiceSubTotal ShippingDate InvoiceDate ShippingCharge ProductStock InvoiceDetailAmount CategoryDiscount InvoiceDetailQuantity ProductPrice No momento de gerar o programa associado na transação “Invoice”. Observemos as 2 últimas regras definidas: Subtract(InvoiceDetailQuantity. InvoiceDetailAmount = InvoiceDetailQuantity *ProductPrice R. ProductStock). também deverá ser recalculada a fórmula correspondente ao desconto (InvoiceDiscount). como este atributo interfere na fórmula que calcula o valor da linha (InvoiceDetailAmount).

Agora. a subtração é realizada quando ele for suficiente. portanto temos que definir que se dispare a mensagem de error se o estoque ficou o stock com valor negativo. porque como sabemos que a subtração será realizada primeiro. Toda regra que atualize o valor de um atributo. Na programação clássica primeiro consulta-se o estoque. CustomerTotalPurchases). Por este motivo é que a regra Error consulta se o atributo ProductStock ficou com valor negativo. e em seguida dispara a que o consulta. Assim que a regra deve definir é: Error(‘Insufficient Stock’) if ProductStock < 0.. já que será executado a subtração no momento de consultar o valor de ProductStock. se ao disparar a regra Subtract o stock que ficará negativo. Então. se dispararia a regra Error. o Subtract que foi executado é desfeito. Seguindo o exemplo que estamos vendo. . se detêm qualquer atualização da base de dados e desarma a árvore de avaliação. Esta sintaxe é correta.Estas regras estão inter-relacionadas porque envolvem o atributo ProductStock. Como conseqüência ao se disparar a regra Error. não é correta sua lógica. enquanto que a segunda somente consulta seu valor. na árvore de avaliação determinada pelo GeneXus primeiro é disparada a regra Subtract e depois a regra Error. Quando se dispara uma regra Error. assim como todas as demais regras e fórmulas que tenham executado (recálculo dos atributos InvoiceDetailAmount.. a primeira o atualiza. Por isso quem está aprendendo GeneXus pode intuitivamente escrever a regra: Error(Insufficient Stock’) if InvoiceDetailQuantity > ProductStock. será disparada antes que uma regra que o consulte (isto pode ser observado claramente na árvore). .... E não: Error('Insufficient Stock') if InvoiceDetailQuantity > ProductStock. a regra que atualiza o atributo será a que vai disparar o primeiro. InvoiceSubTotal. já que como temos explicado. ficando no estado anterior ao se produzir o erro.

Se construirmos a árvore de avaliação correspondente as fórmulas e regra que definimos nesta transação: .. nos interessa controlar que o total que venha escrito na fatura (e que será digitado no atributo InvoiceEntTotal) seja correto. Porém em alguns casos podemos querer alterar o momento de disparo de uma Regra. definimos o atributo InvoiceCalcTotal como fórmula vertical SUM(InvoiceDetailAmount)... já que o número de fatura não nos serve como identificador único.. InvoiceEntTotal Entered Total InvoiceDetailAmount { ProductId* InvoiceDetailQuantity InvoiceDetailPrice InvoiceDetailAmount = InvoiceDetailPrice * InvoiceDetailQuantity} . Para fazer este controle. porque fornecedores distintos podem repetir o mesmo número de fatura.Alterações da ordem de disparo das regras Error Total Calculado Total Ingressado SupplierId* InvoiceId* . O identificador do primeiro nível é composto pelo código do fornecedor e o número de fatura. Para cada fatura de um fornecedor que inserimos. Na maioria dos casos a ordem de execução das regras definida pelo GeneXus a partir de nossas especificações é o desejado. Exemplo: Definimos uma transação para registrar as faturas que recebemos de nossos fornecedores. e agregamos uma regra Error que será disparada se não coincidir os valores dos atributos InvoiceEntTotal e InvoiceCalcTotal: Error(‘The calculated total doesn’t match with the entered total') if InvoiceCalcTotal <> InvoiceEntTotal. InvoiceCalcTotal = SUM(InvoiceDetailAmount) Calculated Total Error(‘The calculated total doesn’t match with the entered total') if (InvoiceEntTotal<>InvoiceCalcTotal) On AfterLevel Level ProductId.

Seguindo o exemplo visto. dispara-se a regra Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal <> InvoiceEntTotal. então. ou de uma linha. recalculamos o valor do atributo fórmula InvoiceCalcTotal que temos definido para ter o total calculado da fatura. Mas o valor calculado do atributo InvoiceCalcTotal não coincidirá com o valor inserido no atributo InvoiceEntTotal até que não tenham ingressado todas as linhas da fatura. existe um evento de disparo que ocorre assim que entramos num nível e saímos do mesmo. Além deste evento de disparo. porque para cada linha que é inserida. que ocorrem antes ou depois de determinada ação. De modo que a regra Error de nosso exemplo. . Agora.vemos que as dependências indicam que cada vez que são inseridos. devendo Atributo um atributo pertencente ao nível interagido e que se abandona. A sintaxe deste evento de disparo é: AfterLevel Level Atributo. As regras das transações podem serem condicionadas de tal maneira que sejam disparadas no momento específico que ocorre algum desses eventos de disparo. altere ou elimine as linhas. e ficaria definida da seguinte forma: Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal<>InvoiceEntTotal On AfterLevel ProductId. não nos serve o determinado na árvore de avaliação. em conseqüência. já que não queremos que seja analisada a condição de disparo da regra Error cada vez que o operador insira. Agregando este evento de disparo a regra controlamos o que se deseja no momento adequado. prestamos atenção a condição de disparo InvoiceCalcTotal<>InvoiceEntTotal vai ser cumprida repetidamente na medida em que o operador vai inserindo as linhas. cumpre a dita condição de disparo e dispara a regra Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal <> InvoiceEntTotal. existem outros que veremos em seguida. e sim necessitamos que seja analisada quando o usuário tenha terminado trabalhar com todas as linhas da fatura. calcula-se o valor do atributo fórmula InvoiceDetailAmount da linha. e como o atributo fórmula InvoiceCalcTotal está envolvido na condição de disparo da regra Error. GeneXus oferece eventos ou momentos de disparo nas transações. como a gravação do cabeçalho. agregaríamos este evento de disparo. Concluímos então que neste caso. modificados ou eliminados valores dos atributos InvoiceDetailAmount e InvoiceDetailQuantity nas linhas. e como consequência é recalculado o valor do atributo fórmula InvoiceCalcTotal. recalcula-se o valor do atributo InvoiceDetailAmount correspondente..

Será colocado no código gerado por GeneXus. Cada transação. AfterUpdate. Ao agregar um evento ou momento de disparo a uma regra. após serem ingressados os dados da primeira. Imediatamente depois será gravado o registro correspondente ao cabeçalho. realiza um commit (é automático). BeforeDelete • AfterInsert. Imediatamente depois desta ação de validação. Eventos de disparo: • BeforeValidate • AfterValidate • BeforeInsert. Análogo é o caso das linhas: “a validação dos dados de uma linha” ocorre após todos serem validados e cada um dos dados da linha. BeforeUpdate. os registros serão comitados. Isto é. ao qual seus registros serão comitados. exceto se o analista especifique o contrário. e depois será ingressado o segundo. &today)). será gravado fisicamente o registro correspondente linha. Os eventos de disparo de regras permitem condicionar o disparo de uma regra da transação para que se execute antes ou depois de alguma das ações que acabamos de enumerar. ProductStock)). e também após terem sido disparadas todas as regras correspondentes segundo a árvore de avaliação (exemplo: subtract( InvoiceDetailQuantity. modificação ou eliminação) • validação dos dados da primeira linha • gravação física dos dados da primeira linha • validação dos dados da segunda linha • gravação física dos dados da segunda linha •… • validação dos dados da n-ésima linha • gravação física dos dados da n-ésima linha • commit A ação de “validação dos dados do cabeçalho” ocorre após todos serem validados e cada um dos campos informados no cabeçalho. se os dados de duas faturas distintas forem ingressados utilizando a transação “Invoice”.Eventos de disparo A maioria das regras nas transações permitem agregar um evento ou momento de disparo. estaremos especificando que a regra deve ser executada nesse determinado momento. ocorre uma série de ações que é necessário para poder programar corretamente o comportamento das regras. Veremos quando ocorre cada evento de disparo. poderíamos enumerá-las como segue: • validação dos dados do cabeçalho • gravação física do cabeçalho (seja inserção. ao terminar de trabalhar com um cabeçalho e suas linhas. Para uma transação de dois níveis. . Observar que neste ponto já foi disparado todas as regras que correspondiam aos atributos do cabeçalho e que não tinham evento de disparo associado (exemplo: Default(InvoiceDate. AfterDelete • AfterLevel • BeforeComplete • AfterComplete No momento da confirmação da transação. como veremos mais adiante.

Nesses casos que não contamos com a possibilidade de utilizar a Propriedade Autonumber e necessitamos numerar de forma automática e correlativa certos atributos. BeforeInsert. O procedimento devolveria o número 6. BeforeUpdate. tem somente um atributo envolvido que pertence ao primeiro nível das transações “Customer” e “Invoice” respectivamente). Eventos de disparo: AfterValidate. Tal funcionalidade é prevista pelos administradores de base de dados (DBMSs) e o GeneXus a aproveita e permite usá-la. esse número 6 seria perdido e a próxima fatura. Em outras palavras. Observar que aqui também haverão disparadas todas as regras segundo a árvore de avaliação que não estejam condicionadas com nenhum evBeforeento de disparo. Neste caso se está querendo serializar o atributo CustomerId da transação “Customer” Do mesmo modo. que deveria ter o número 6 não o terá. tentando desta forma ter o maior grau de segurança possível ao número atribuído que será utilizado (e não perder números). porque o primeiro atributo do cabeçalho é utilizado. a transação vai fazer com que seja criada uma tabela.udp( ‘CUSTOMER’ ) if Insert on AfterValidate. e se ao validar os dados do cabeçalho encontrar algum error que não permita continuar com o processo.udp( ‘INVOICE’ ) if Insert on AfterValidate. Para chamar ao procedimento de numeração automática se deve definir nas transações que o requerem a seguinte regra: CustomerId = PGetNumber. nos casos em que não trabalhamos com um administrador de base de dados. altere ou elimine) como registro na tabela física associada ao nível. com a transação "Number” que era a que tinha o literal: NumberCode e o último número atribuído a transação correspondente a esse literal: NumberLast . Para fazê-lo somente definindo uma transação contendo ao menos dois atributos. se queremos serializar o identificador de faturas. EXEMPLOS 1. por exemplo. Caso a regra fosse disparada sem ter condição. a regra de atribuição com udp chama o procedimento de numeração que seria disparado assim que ingressar na transação com modo insert. Ou seja. e sim o número 7. se o número da fatura anterior for 5 e o usuário quer informar a seguinte fatura. A resposta é simples: um número seria perdido. a mesma executará. um para armazenar um literal e outro para armazenar o último número atribuído automaticamente ao atributo descrito pelo literal1. some um e devolva o próximo número. ocorrerá antes da ação de “validação do cabeçalho” ou “validação da linha”. na tabela física correspondente e depois de ter validado os dados desta instancia. e temos que definir um procedimento que consulte essa tabela. obtenha o último número atribuído para o atributo a ser numerado. correspondente. O motivo pelo qual agregamos o evento de disparo on AfterValidate a estas regras é para chamar o procedimento de numeração automática imediatamente antes de que seja inserido o registro na base de dados e depois da validação.Evento de disparo: BeforeValidate Este evento de disparo ocorre um pouco antes da informação da instancia que se trabalhe (cabeçalho ou linha) seja validada (ou confirmada). Isto é. para cada instancia do nível ao qual esteja associada a regra. abandonar a transação.Tem vezes que não contamos com a possibilidade de utilizar a Propriedade Autonumber para numerar de forma automática e correlativa os atributos que são chave primária simples. além de atualizá-lo na tabela. não temos a possibilidade de selecionar esta facilidade. agregando o evento de disparo AfterValidate a uma regra. escreveríamos na transação “Invoice” com a seguinte regra: InvoiceId = PGetNumber. Desta forma definimos que se efetuam numerações automáticas nas transações unicamente quando se realizem inserções (pela condição de disparo: if Insert) e imediatamente antes do registro ser gravado fisicamente cada instancia a ser inserida (pelo evento de disparo: on AfterValidate) através do primeiro nível da transação (porque nas duas regras de chamadas que foram mostradas. devemos resolver nós mesmos na programação. BeforeDelete O evento de disparo AfterValidate permite definir que uma regra seja executada imediatamente antes de que gravemos fisicamente cada instancia do nível ao qual está associada a regra. imediatamente antes de que a instancia seja gravada fisicamente (seja quando insere. ________________________________________________________________________________________ 1 Quando vimos a regra serial falamos este tema de numeração de cabeçalho. e no caso de faltar alguma validação dos dados do cabeçalho.

BeforeDelete. BeforeInsert. ou o encontraria com seus dados desatualizados (caso estivesse modificando um cliente por meio da transação). Se na alteração estivesse eliminando um cliente por meio da transação.udp( 'INVOICE' ) on BeforeInsert. as seguintes equivalências são válidas: on BeforeInsert ∼ on BeforeUpdate on BeforeDelete If Insert on AfterValidate ∼ If Update on AfterValidate ∼ If Delete on AfterValidate Se tivermos um esquema das ações que rodeiam o disparo do evento. Em conseqüência. Não é adequado agregar-lhe este evento de disparo a regra de chamadas ao relatório. também existem eventos de disparo para definir que certas regras sejam executadas imediatamente depois de que sejam inseridas. modificadas ou eliminadas fisicamente instancias de um nível. O evento de disparo AfterInsert permite definir que uma regra execute imediatamente depois de que seja inserida fisicamente cada instancia do nível ao qual está associada a regra. mas a diferença dos exemplos recém vistos. se dispare no nível seguinte. é referenciado na regra pelo menos um atributo do segundo nível da transação na qual está definindo a regra. e o AfterDelete depois de eliminar. Caso desejarmos emitir uma lista com os dados de cada cliente que forem eliminados. delete segundo corresponda) 2) Se definirmos uma regra em que incluímos também o evento de disparo on AfterValidate.Existem 3 eventos de disparo que ocorrem no mesmo momento que o AfterValidate. AfterUpdate e AfterDelete. Em que momento devemos realizar as chamadas ao relatório a partir da transação? Caso 1: RPrintCustomer. update. porque o mesmo seria chamado imediatamente antes da gravação física de cada cliente. É equivalente escrever a regra apresentada como: InvoiceId = PGetNumber. a mesma estará associada ao segundo nível1. Portanto. São eles: BeforeInsert. a regra executará imediatamente antes que seja gravada fisicamente cada instancia correspondente ao segundo nível da transação. Portanto. por meio de cláusula Level que foi mencionado quando vimos conceitos importantes sobre as regras de transações. Eventos de disparo: AfterInsert. Estes eventos são AfterInsert. AfterDelete Assim como existe um evento de disparo que permite definir que determinadas regras sejam executadas imediatamente antes que seja produzida a gravação física de cada instancia de um nível (AfterValidate. o AfterUpdate depois de atualizar fisicamente a instancia. ou on BeforeInsert. EXEMPLOS Vamos supor que na transação “Customer” queremos chamar um relatório que realize a impressão dos dados de cada cliente com o qual trabalhamos por meio da transação.call( CustomerId ) if delete on AfterValidate.call( CustomerId ) on AfterValidate. ou equivalente: RPrintCustomer. . BeforeUpdate e BeforeDelete. o relatório não encontraria o cliente com seus dados na tabela CUSTOMER (caso estivesse inserindo um cliente por meio da transação). BeforeUpdate e BeforeDelete). o relatório encontraria os dados do cliente na tabela CUSTOMER e os listaria justamente antes da atualização física (eliminação). tempo ________________________________________________________________________________________________ 1 Existe outra forma de provocar que uma regra que contem atributos de um nível determinado. ficam claros os dois sinônimos escolhidos para este evento (AfterValidate e BeforeInsert para modo insert) VALIDAÇÃO DOS DADOS AfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete GRAVAÇÃO DO REGISTRO (insert. Observar que aqui é redundante condicionar a regra a “If Insert”.call( CustomerId ) on BeforeDelete. AfterUpdate. seria adequado definir a seguinte regra: RPrintCustomer. BeforeUdate. mas já possuem o modo de forma intrínseca.

Call( CustomerId ) on AfterInsert.Call( CustomerId ) on AfterInsert.Call( CustomerId ) if delete on AfterValidate. como o único atributo envolvido na regra é CustomerId. O evento de disparo AfterInsert ocorre imediatamente depois de que inserimos fisicamente cada instancia associada a certo nível da transação (neste caso. Caso 2: RPrintCustomer. Como indica claramente pelo seu nome. não é necessário agregar-lhe a condição de disparo if insert. o evento de disparo AfterInsert somente ocorre ao inserir uma nova instancia (precisamente após ser inserida como registro físico).Call( CustomerId ) on AfterDelete. Assim que o relatório encontrar o cliente com seus dados na tabela CUSTOMER e os imprime. Caso 4: RPrintCustomer. quando os mesmos aplicam a uma mesma regra. que esta regra: RPrintCustomer. como o único atributo envolvido na regra é CustomerId. como o único atributo envolvido na regra é CustomerId. O evento de disparo AfterUpdate ocorre imediatamente depois que é atualizada fisicamente cada instancia associada a certo nível da transação (neste caso. Assim que o relatório encontrar o cliente com seus dados atualizados na tabela CUSTOMER e os imprimir. RPrintCustomer. Isto é. Como podemos observar na primeira regra. já que o relatório seria chamado imediatamente depois de que fosse inserido fisicamente cada cliente. AfterUpdate. o relatório não encontra o cliente com seus dados na tabela CUSTOMER. trata-se de uma regra associada ao primeiro e único nível da transação “Customer”). Utilizando ele quando se agrega o evento de disparo on AfterInsert a uma regra. estas duas regras são adequadas para chamar um relatório na transação “Customer”.Call( CustomerId ) on AfterInsert.Call( CustomerId ) on AfterInsert. o relatório é chamado unicamente logo que realizar inserções. É adequado agregar neste evento de disparo a regra de chamadas ao relatório. porque é o único caso em que seria correto utilizar o evento de disparo AfterValidate (já que justamente necessitamos emitir o relatório antes da eliminação). se trata de uma regra associada ao primeiro e único nível da transação “Customer”).Call( CustomerId ) on AfterUpdate.Call( CustomerId ) on AfterUpdate. Para finalizar. RPrintCustomer. É correto agregar este evento de disparo a regra de chamadas ao relatório. já que o relatório é chamado imediatamente depois que for atualizado fisicamente um cliente. Caso 5: RPrintCustomer. com o objetivo de imprimir os dados de cada cliente com qual trabalhar. se trata de uma regra associada ao primeiro e único nível da transação “Customer”).para restringir o disparo da regra unicamente quando estamos eliminando um cliente. abrangendo os três modos de trabalho. Em conseqüência. O que deve ficar claro é que com esta definição. O relatório será chamado unicamente após realizar as atualizações. Não é adequado agregar este evento de disparo a regra de chamadas ao relatório. AfterUpdate. é possível incluir vários eventos de disparo separados por vírgula. é o mesmo que definir duas regras independentes: RPrintCustomer. . Caso 3: RPrintCustomer. O evento de disparo AfterDelete ocorre imediatamente depois da eliminação física de cada instancia associada a certo nível da transação (neste caso. porque o relatório é chamado imediatamente depois da eliminação física de cada cliente.

A ação depois da última linha seria gravada é quando sai desse nível (neste caso as linhas da fatura). é referenciada na regra pelo menos um atributo do segundo nível da transação na qual estamos definindo a regra. delete segundo corresponda) AfterInsert – AfterUpdate – AfterDelete VALIDAÇÃO DOS DADOS LINHA AfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete GRAVAÇÃO DO REGISTRO (insert. podemos pensar num loop que se repete até que a última linha seja gravada. update. a regra é executada imediatamente depois de que inserimos fisicamente cada instancia correspondente ao segundo nível da transação. Ampliamos o esquema que havíamos efetuado antes. das ações que rodeiam aos eventos de disparos visto até agora: VALIDAÇÃO DOS DADOS AfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete GRAVAÇÃO DO REGISTRO (insert. update. Entre a ação de abandonar o nível. nesse caso voltaria o esquema anterior. e o commit temos um evento (que admite dois nomes distintos) e outro para depois do commit. a mesma estará associada ao segundo nível.BeforeComplete COMMIT AfterComplete tempo loop . E depois dessa ação. Por exemplo. Este esquema ocorre para cada linha. mas a diferença dos exemplos vistos recentemente. exceto que tenha outro nível. Portanto. São o que veremos na continuação mas que já vamos mostrar no esquema: VALIDAÇÃO DOS DADOS CABEÇALHO AfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete GRAVAÇÃO DO REGISTRO (insert. ocorrerá o commit que é a última ação de execução. delete segundo corresponda) AfterInsert – AfterUpdate – AfterDelete tempo Este esquema se repete para cada instancia do nível. Analogamente é o caso de disparo de on AfterUpdate e on AfterDelete. pensamos no ingresso das linhas de uma fatura. delete segundo corresponda) AfterInsert – AfterUpdate – AfterDelete ABANDONAR NÍVEL 2 AfterLevel .Caso 6: Se definirmos uma regra a qual incluímos o evento de disparo on AfterInsert. update.

o evento de disparo apropriado será AfterLevel att. uma vez que tivermos inserido todos os cabeçalhos e suas linhas e fechado a transação (nesse momento terão interagido todos os cabeçalhos). a regra será executada quando terminar de interagir com todas as linhas do segundo nível. que necessitamos que se dispare depois de todas as linhas da fatura do Fornecedor serem informadas. . Neste caso o evento BeforeComplete coincidirá com o AfterLevel Level CustomerEMail. BeforeComplete O evento de disparo AfterLevel permite definir que uma regra seja executada imediatamente depois de terminar de interagir determinado nível. ocorrerão 3 commits (um no final de cada ingresso de cabeçalho + linhas) e 3 eventos AfterComplete. Observar que isto ocorre no final de tudo. Evento de disparo: AfterComplete Este evento corresponde ao instante de tempo que acontece o commit. se o atributo especificado pertencer ao primeiro nível. coincide com o AfterLevel. Cuidado que isto é sempre assim e quando o nível abandonado é o último. São 02 (dois) nomes para nos referimos ao mesmo. And. constantes e funções. .seguindo o mesmo conceito . quando estudarmos integridade transacional. Portanto. onde tínhamos uma transação para representar as Faturas dos fornecedores. variáveis. podemos ver que o tempo que tem entre sair do último nível e a realização do commit é o instante que ocorrem estes eventos. neste caso. se execute a regra.Eventos de disparo: AfterLevel. SINTAXE: regra [if condição de disparo] [on AfterLevel Level atributo]. FUNCIONALIDADE: Se o atributo que especificamos na continuação do evento de disparo AfterLevel pertencer ao segundo nível da transação. a segunda se disparará depois de sair deste último nível. assim como os operadores Or. ou seja. à regra será disparada uma vez somente antes do Evento Exit (é um evento que executa uma vez quando fechamos uma transação em tempo de execução. Not. ONDE: regra: é uma regra das permitidas em transações condição de disparo: é uma expressão booleana que permite envolver atributos. Exemplo: Rever o exemplo apresentado anteriormente. onde att pode ser qualquer atributo das linhas. Portanto. se ingressam 3 faturas (cabeçalho e suas respectivas linhas) e fecha a transação. como veremos). Enquanto que a primeira se dispara ao sair do nível dos telefones. Tínhamos a regra: Error(‘The calculated total doesn’t match with the entered total ') if InvoiceCalcTotal<>InvoiceEntTotal. Se observarmos o esquema apresentado na página anterior. e antes de entrar a validar todos os emails. E se o atributo especificado em seguida do evento de disparo AfterLevel pertencer ao primeiro nível.a regra será executada quando tenha terminado de interagir com todos os cabeçalhos. O evento de nome BeforeComplete. Se abrir a transação de faturas. Por exemplo uma transação com dois níveis paralelos. e onde tínhamos que controlar que o total calculado de cada fatura coincida com o total informado. Se agregamos ao cliente suas direções de mail e seus números telefônicos (pode ter vários): CustomerId* CustomerName … {CustomerPhone* …} {CustomerEMail* …} O momento em que deverá disparar uma regra condicionada a: On AfterLevel Level CustomerPhone NÃO COINCIDIRÁ com o de uma regra condicionada a on BeforeComplete. Falaremos mais deste evento umas páginas adiantes. atributo: é um atributo pertencente ao nível para o qual se deseja que depois de ser iterado.

seguindo a ordem que esta determina. O disparo de regras e fórmulas irá sendo feito de acordo com a árvore de avaliação.Exemplo em uma transação de 2 níveis Interativamente e antes de confirmar: REGRAS STAND-ALONE AVALIAÇÃO DE REGRAS E FÓRMULAS SEGUNDO ÁRVORE PARA CADA LINHA AVALIAÇÃO DE REGRAS E FÓRMULAS SEGUNDO ÁRVORE O seguinte exemplo pretende mostrar visualmente em que momentos serão disparadas as regras e fórmulas definidas numa transação. .

ou os BeforeInsert. serão executadas todas as regras que tenham como evento de disparo BeforeValidate. Como exemplo. · &A = 7. Portanto. seguindo a ordem de dependências determinado por GeneXus (assim como as fórmulas associadas ao primeiro nível)..’ ) if parâmetro1 = 7. . Exemplos de regras stand alone (não dependem de nada para serem executadas) : · msg( ‘You are in the invoice transaction’).. Depois da execução das regras stand alone. Podem executar-se com a informação prevista pelos parâmetros recebidos. que não tenham evento de disparo definido. Não dependem de nada para serem executadas.” Depois de executadas as regras mencionadas para o cabeçalho. 2. Exemplos de regras stand alone (poder executar com a informação prevista pelos parâmetros): · &A = parâmetro2. · Msg( ‘. dependendo do modo em que esteja. se executam as regras associadas ao primeiro nível da transação.Exemplo em transação de 2 níveis Ao confirmar os dados.BeforeComplete COMMIT AfterComplete Regras stand alone As regras stand alone são aquelas que: 1. &Today). BeforeUpdate. Por exemplo: Se não podemos serializar as faturas com a propriedade Autonumber porque o DBMS escolhido não suporta: InvoiceId = PGetNumber. são as primeiras regras que podem ser executadas. já que imediatamente depois ocorre a ação de validação (ou confirmação) da informação desse primeiro nível. Imediatamente depois da validação do primeiro nível se executam as regras associadas ao primeiro nível da transação que incluam em sua definição o evento de disparo AfterValidate. BeforeDelete. na seguinte ordem são executados: REGRAS STAND-ALONE AVALIAÇÃO REGRAS E FÓRMULAS SEGUNDO ÁRVORE BeforeValidate VALIDAÇÃO AfterValidate / BeforeInsert / Update / Delete GRAVAÇÃO DO CABEÇALHO AfterInsert / Update / Delete AVALIAÇÃO DE REGRAS E FÓRMULAS SEGUNDO ÁRVORE PARA CADA BeforeValidate LINHA VALIDAÇÃO AfterValidate/BeforeInsert/Udpate/Delete GRAVAÇÃO DA LINHA AfterInsert/Update/Delete ABANDONAR NÍVEL 2 AfterLevel Level attNivel2 . se dispara a regra: “Default( InvoiceDate.udp(‘INVOICE’) on BeforeInsert.

como é o caso do exemplo.Após a execução das regras associadas ao primeiro nível com alguns destes eventos de disparo executa-se a ação de gravação. Em seguida a execução das regras associadas ao segundo nível com algum destes eventos de disparo será executada a ação de gravação. serão executadas para cada uma das linhas: Em primeiro lugar. a fórmula InvoiceDetailAmount = InvoiceDetailQuantity*ProductPrice. Sendo uma transação de dois níveis. seguindo a ordem de dependências determinado pelo GeneXus (assim como as fórmulas associadas ao segundo nível). · se a gravação correspondeu a uma eliminação: executarão as regras associadas ao primeiro nível da transação com evento de disparo AfterDelete. na tabela: INVOICEDETAIL). • se a gravação correspondeu a uma atualização: são executadas as regras associadas ao segundo nível da transação com evento de disparo AfterUpdate. como neste caso. Se não existir outro nível. então coincidirá com o evento de disparo BeforeComplete . serão executadas as regras associadas ao segundo nível da transação que incluam em sua definição algum dos eventos de disparo: AfterValidate. BeforeDelete. Após dela são executadas as regras definidas com evento de disparo AfterLevel Level Atributo do 2do nível. isto é. ou seja. Imediatamente depois de ter gravado a instancia correspondente a linha como registro físico na tabela correspondente: • se a gravação correspondeu a uma inserção: são executadas as regras associadas ao segundo nível da transação com evento de disparo AfterInsert. serão executadas todas as regras que tenham como evento de disparo BeforeValidate. podemos supor a existência de uma ação que poderíamos chamar abandono do segundo nível. na tabela: INVOICE). Depois das regras mencionadas executadas para uma linha. Imediatamente depois de ter gravado a instancia: · se a gravação correspondeu a uma inserção: executarão as regras associadas ao primeiro nível da transação com evento de disparo AfterInsert. · se a gravação correspondeu a uma atualização: executarão as regras associadas ao primeiro nível da transação com evento de disparo AfterUpdate. Após a interação de todas as linhas. BeforeInsert. • se a gravação correspondeu a uma eliminação: são executadas as regras associadas ao segundo nível da transação com evento de disparo AfterDelete. as regras associadas ao segundo nível da transação que não tenham evento de disparo definido. são executadas na ordem descrita. BeforeUpdate. que gravará fisicamente a instancia correspondente ao primeiro nível da transação como registro físico na tabela correspondente (neste exemplo. Exemplos disso são a regra: Subtract( InvoiceDetailQuantity. gravará fisicamente a instancia correspondente a linha como registro física na tabela correspondente (neste exemplo. Todas estas operações sombreadas de cinza claro. visto que imediatamente depois ocorre a validação da linha. ProductStock ). Imediatamente depois da validação da linha. para cada uma das linhas. isto é uma ação que ocorre depois de terminar de trabalhar com a linha.

um commit é efetuado. e que ações ocorrem antes e depois de cada evento de disparo. para cada uma das linhas depois que se tenham gravado. É indispensável assimilar fortemente em que ordem se executam as regras em uma transação. abandono do segundo nível (sair do segundo nível) e commit. poderá programar o comportamento das transações adequadamente. Posteriormente. É fácil compreender que se necessitamos programar determinados controles ou ações nas transações.Declaração Importante: Todas as operações sombreadas. As mesmas são: validação. Após de ser executada todas as operações explicadas até o momento. seja em uma transação de um nível ou de dois. modifique ou elimine) Pode ser útil saber que serão ressaltadas em negrito as ações cada vez que se tenha mencionado. depois de gravar o mesmo. sabemos que tais operações não são executadas. quais são os eventos de disparo disponíveis para atribuir. serão executadas na ordem que foi descrito. gravação. para cada fatura com a qual se trabalhe por meio da transação “Invoice” (seja quando se insere. é para diferenciar o conjunto de operações que são executadas para cada uma das linhas (sombreado cor clara) das operações que são executadas somente uma vez ao terminar de interagir com as linhas (sombreado com cor mais escura). ou antes. quando são disparadas exatamente. É de fundamental importância que fique claro que todas as operações explicadas. O motivo dos dois sombreados distintos. explicaremos as demais operações que são executadas. portanto é fundamental ter bem claro todo este tema. ou antes. depois do commit. de modo que se for uma transação de um nível. teremos que saber bem se será feito antes de gravar o cabeçalho. tanto de cor clara como de cor escura. Na continuação serão executadas as regras com evento de disparo AfterComplete. já que somente conhecendo bem todo este tema. executam-se unicamente quando for uma transação de dois níveis. .

Depois de disparar todas as regras e fórmulas segundo árvore.call( InvoiceId. .call( InvoiceId ) on BeforeInsert.call( InvoiceId ) if Insert. • Something. e validar todos os dados do cabeçalho. Observar que Level ProductId especifica que se está falando do BeforeInsert das linhas e não do cabeçalho. e validados todos os dados da linha. Depois que todas as regras e fórmulas segundo a árvore serem disparadas. • Something. Ocorre um instante antes de inserir o registro.Exemplos Quando são disparadas as regras seguintes? • Something. Idem ao anterior. Ocorre um instante antes do registro ser inserido.call( InvoiceId ) on BeforeInsert Level ProductId. ProductId ) on BeforeInsert. Depois de validar o campo InvoiceId e inferido que se está em modo Insert • Something.

call( InvoiceDate ) on AfterInsert. isto é. Mas o evento de disparo condiciona que seja executada ao sair das linhas. é disparado para cada linha. Correto: aqui está sendo passado o valor de um atributo do cabeçalho. Quais? • InvoiceDate = &today on AfterInsert. o evento de disparo está associada ao 2do. Incorreto: a regra. enquanto estiver na instância da fatura esse valor está na memória.call( InvoiceId. ProductId ) on AfterLevel Level ProductId.Exemplos Algumas regras estão mal programadas. Último momento possível para utilizá-lo é no AfterComplete. • Something. Qual valor teria ProductId? . Nível. Incorreto: O último momento para atribuir valor a um atributo do cabeçalho é imediatamente antes de sua gravação (BeforeInsert) • Something.

‘yyy’. Para resolver isto. e não existe nenhuma dependência entre elas.call(CustomerId. 2) Em uma transação. • Exemplo 2 ‘pgmname’. &flag) On AfterComplete. e não existe nenhuma dependência entre elas.call() On AfterComplete. Regras com o mesmo evento de disparo Quando em uma transação definimos duas ou mais regras com o mesmo evento de disparo.1) Definir as regras: Pgmname. Como as duas regras definidas estão condicionadas ao mesmo evento de disparo.Regras com o mesmo evento de disparo • São disparadas na ordem em que foram definidas • Exemplo 1 ‘xxx’.Call() on AfterComplete.Call() on AfterComplete. avaliaremos duas possibilidades: 2. caso seja necessário chamar a um procedimento que realiza determinada validação e retorna um valor ‘S’ ou ‘N’. elas serão executadas na mesma ordem em que foram escritas. as mesmas serão executadas respeitando a ordem de definição. e se o valor devolvido é ‘N’. ‘yyy’. &flag) on AfterComplete.call( CustomerId. error(' ') if &flag = 'N’ On AfterComplete. Error(“ “) if &flag=”N” on AfterComplete. Exemplos: 1) Se definem as seguintes regras em uma transação: ‘xxx’.call() On AfterComplete. aparecerá uma mensagem de erro. .

e a variável &flag se passa por parâmetro na regra call.que é onde encontram-se as regras vista até então -. então.1). e em seguida dispara a regra error (caso cumpra-se a condição de disparo). em conseqüência o especificador não encontrará inter-dependência entre as regras call e error. já que a regra de error está condicionada ao valor da variável &flag. ou de entrada-saída. Ambas regras tem o mesmo evento de disparo. Error(“ “) if &flag = ”N” on AfterComplete. A respeito da segunda alternativa. se utilize udp ao invés de call. e logo que esta variável tenha valor. e nesse caso por Exemplo. observemos que consiste em uma regra udp e uma regra error. de saída. não haveria uma dependência de que primeiro deve-se executar a regra call e depois a regra error. se as regras call e error estiverem escritas em ordem inversa (primeiro a regra error e depois a regra call). o especificador do GeneXus não pode saber se os parâmetros passados em um call são de entrada. em muitos casos o comportamento não será o esperado. No caso 2. já que a regra error está condicionada ao valor da variável &flag. ou não. Por esta razão recomendamos que sempre que se quer definir validações desse tipo. . para o especificador do GeneXus fica claro que a variável &flag volta modificada do procedimento. Concluindo.2) Ou definir as regras: &flag = Pgmname. independentemente da ordem de definição de ambas as regras.2. porque as mesmas serão disparadas na Ordem em que estão escritas. e neste caso se existir dependência entre elas. já que a variável &flag poderia ser passada como variável de entrada ao procedimento.2). É importante ver que. na seção de regras da transação . porque a variável &flag é carregada mediante a chamada ao procedimento com udp. o especificador do GeneXus entende que primeiro deve-se disparar a chamada ao procedimento com udp e depois a regra error. é que será avaliada a necessidade de disparar a regra error. e como as chamadas ao procedimento realizam-se com udp. a dependência pode parecer evidente porque no procedimento programamos a variável &flag. Todavia. a chamada ao procedimento com udp é disparada primeiro. não se detectam dependências entre as regras call e error da alternativa 2. Ambas regras tem o mesmo evento de disparo. de saída. portanto.udp(CustomerId) on AfterComplete. Na primeira alternativa. e aparentemente existiria dependência entre elas. temos definida uma regra call e uma regra error.

O código que pode ser associado a um evento. . é escrito de forma procedural. provoquem que o código definido seja executado. que é um estilo de programação na qual se define código que permanece ocioso. Os eventos são ações reconhecidas por um objeto que podem acontecer ou não. até que os eventos provocados pelo Usuário ou pelo sistema. e quando o evento for produzido. que será executado somente caso o evento se produza. o código associado ao mesmo será executado seqüencialmente. A cada evento podemos associar o código.Eventos em Transações Nas transações permite-se a programação dirigida por eventos.

Por esta razão. ou se é a nésima. ao final da mesma. se disparará o evento Start cada vez que se envie ao servidor a informação da instancia com a qual estiver trabalhando. não é possível saber se está ingressando a primeira instancia de uma fatura. O evento TrackContext é aplicado para obter interfaces de usuário sensíveis ao contexto.Eventos em Transações • Evento Start • Evento ‘User Event’ • Evento After Trn • Evento Exit • Evento TrackContext Como em Web não se mantém um estado no servidor que permita saber o que está sendo executado no cliente. . Enquanto que no evento Exit. Programando este evento pode-se receber informação do contexto para depois tomar as decisões necessárias. se excuta por cada iteração.

o resultado da função Now() que devolve a data e hora atual: Event Start &entrada = Now() EndEvent Se executa cada vez que se submeta o form da transação. . Para isso no evento Start o atribuímos a uma variável de nome &entrada e tipo de dados DateTime.Eventos Start • Start: Executado cada vez que o form de uma transação é submetido ao servidor. seja para avaliá-los e/ou usá-los de algum modo exceto para atualizá-los. Já a utilização dos atributos neste evento. pois todavia não foi editado a instancia da transação. quando o usuário pressionar qualquer botão do form. se deve considerar que os únicos atributos que estão disponíveis são os que são recebidos por parâmetro na regra parm. EXEMPLO: Em uma transação nos interessa capturar a data e hora de entrada da mesma. ou seja. Notas gerais: No evento Start fundamentalmente se trabalha com variáveis. ocorre automaticamente. Nenhum outro atributo terá valor neste evento. SINTAXE: Event Start código EndEvent EXEMPLO: Event Start &entrada=Now() EndEvent O evento Start é um evento do sistema.

ou se pode criar um novo. Leitura de atributos e variáveis do form 3. selecionar onde diz OnClickEvent um dos eventos existentes.Call( InvoiceId ) EndEvent Como associar um evento de usuário a um controle? Além dos botões. . Evento Start 2.Eventos de Usuário • Além dos eventos oferecidos por GeneXus. pressionando F7 (isto somente é válido para Win): Event ‘Print Invoice’ // evento definido na transação "Invoice" PrintInvoice. o analista pode definir eventos criados por ele. Evento de usuário selecionado Como pode-se observar na sintaxe. Para realizar a associação se deve inserir o controle correspondente no form Web e depois nas propriedades do controle. EXEMPLO: Se deseja que na transação "Invoice". também as imagens e os text blocks admitem a associação de evento de usuário. deve-se dar um nome a um evento do usuário. após a palavra Event. o usuário possa imprimir a fatura com a qual esteja trabalhando. que encontra-se entre aspas simples. chamados eventos de usuário. Propriedades Web: Ordem de execução 1.

e não definir regras com evento de disparo AfterComplete 3. O primeiro motivo é que já foi realizado as gravações correspondentes e incluso o COMMIT já foi realizado. Em seguida. nos eventos não é permito realizar atribuições aos atributos. Existem as seguintes alternativas para programar comportamentos que desejam ser executados no final de cada interação completa por meio de uma transação: 1. ou avaliar seu valor. os valores dos atributos do primeiro nível da transação são conhecidos. será executado depois que termine cada interação completa por meio da transação (assim que é gravado cada cabeçalho com suas correspondentes linhas como registros físicos nas tabelas que corresponda e de se ter efetuado o COMMIT). Definir regras individuais com evento de disparo AfterComplete e deixar o evento After Trn sem código 2. Um conceito que é muito importante ter claro é que tanto nas regras com evento de disparo AfterComplete como no evento After Trn. ________________________________________________________________________________ 1 Existem dois motivos pelos quais não é possível atualizar atributos em regras com evento de disparo AfterComplete e After Trn. . Ou seja. podendo ser utilizados para passar por parâmetro em uma chamada. e imediatamente após. serão gravados fisicamente os registros correspondentes ao cabeçalho e as linhas de certa interação completa. • Sintaxe: Event After Trn código Endevent • Exemplo: Event After trn Return EndEvent O evento After Trn das transações ocorre imediatamente depois da execução das regras com evento de disparo AfterComplete. Definir todas as sentenças no evento After Trn com estilo procedural. Além disso. primeiro são executadas as regras definidas com evento de disparo AfterComplete. exceto atualizá-los ¹. de modo que já é tarde para atribuir valores aos atributos. ainda temos disponíveis os valores dos atributos do primeiro nível. Definir as duas coisas: algumas regras com evento de disparo AfterComplete e código no evento After Trn Como vemos explicando. inclusive se efetuou COMMIT. o código incluído neste evento. ou usar de algum modo. relacionado ao evento After Trn. executamos as regras com código definido no evento After Trn.Evento After Trn • Ocorre imediatamente depois da execução das regras com evento de disparo AfterComplete.

ou aqueles da estendida permitidos pela regra update) · mediante regras definidas pelo programador (a atributos das tabelas bases associadas a transação e suas estendidas) Os eventos Start e Exit são sem tabela base. Então. exceto os recebidos por parâmetro. ________________________________________________________________________________________________________________________ 1 Se num evento de usuário são referenciados atributos de um segundo nível ou outro nível subordinado. Ao contrário. que assim que se disponha dos valores de certos atributos ou outros dependendo do evento. em nenhum evento (não somente das transações. em particular no evento After Trn.Não é permitido atribuir valores a atributos nos eventos. conhecemos os valores dos atributos do primeiro nível (o segundo nível já foi inserido a essa altura e não tem possibilidade de posicionamento em alguma linha em particular). os mesmos poderão ser utilizados para ser analisados e/ou passados por parâmetro a objetos que se chamem. Concluindo. Com esta expressão nos referimos que nos eventos Start e Exit não tem consulta ativa à base de dados (já que no evento Start ainda não foi feito a consulta e no evento Exit em Win já foi fechado o programa associado a transação e em Web a instancia está sendo fechada e já não dispõe da consulta). quando os mesmos se executam temos uma consulta feita. assim serão estes os valores dos atributos considerados. Por este motivo é que não conhecemos valores de atributos nos eventos Start e Exit. Caso o usuário não se posicionou explicitamente em determinada linha. mas em nenhum objeto GeneXus) permite-se realizar atribuições a atributos. os eventos After Trn e de Usuário são com tabela base. através do form (somente atributos das tabelas bases associadas a transação. quando o evento de usuário for executado nos atributos daquela linha se tem um posicionamento. É fundamental que fique claro. por default a linha que selecionada é a primeira linha. e/ou para alguma outra operação qualquer que não seja atribuir valor. em tempo de execução. e no que diz respeito aos eventos de Usuário os atributos de todos os níveis 1 estão disponíveis. Os valores dos atributos podem ser modificados nas transações: · o usuário final fazendo. . no momento que o evento de usuário é executado serão considerados os valores dos atributos desta linha.

Integridade Transacional IT 143 .

O que é o conceito: integridade transacional? • É um conjunto de atualizações de integridade transacional que a base de dados possui quando acontece uma finalização “anormal”. 144 . Muitos administradores de bases de dados (DBMSs) contam com sistemas de recuperação antifalhas. a base de dados permanece em estado consistente. que permitem deixar a base de dados em estado consistente quando ocorrem imprevistos tais como apagões ou quedas do sistema.

O que é o conceito: unidade lógica de trabalho (UTL)? • Uma Unidade Lógica de Trabalho (UTL) é um conjunto de operações na base de dados. nem mais nem menos. Os administradores de bases de dados (DBMSs) que oferecem integridade transacional. permitem estabelecer Unidades Lógicas de Trabalho (UTLs). todas devem ser executadas ou nenhuma delas. que são. 145 . que o conceito de transações de base de dados.

. Efetuar COMMIT em uma base de dados. Operação sobre Base de Dados Operação sobre Base de Dados COMMIT Finaliza UTL Começa UTL Operação sobre Base de Dados Operação sobre Base de Dados Operação sobre Base de Dados Operação sobre Base de Dados COMMIT Finaliza UTL • Efetuar COMMIT em uma base de dados.. 146 ..... significa finalizar uma Unidade Lógica de Trabalho (UTL). significa finalizar uma Unidade Lógica de Trabalho (UTL)....O que é efetuar COMMIT? • O comando COMMIT permite especificar que certo conjunto de operações realizadas sobre uma base de dados que foram efetuadas corretamente: ..

O que é efetuar ROLLBACK? • Fazer ROLLBACK (voltar atrás) implica em desfazer todas as operações efetuadas na base de dados que não tenham recebido COMMIT. 147 . • Isto resolve-se desfazendo todas as operações posteriores ao último COMMIT.

imediatamente antes das regras com evento de disparo AfterComplete (*) uma exceção Business Components.Unidade lógica de trabalho (UTL) por default em GeneXus Todo objeto GeneXus transação e todo objeto GeneXus procedimento. O motivo disto é que em ambientes Cliente/Servidor. Ou seja. Nota: o novo tipo de dados Business Component que estaremos vendo depois permite atualizar a base de dados desde qualquer objeto GeneXus. somente em ambientes de trabalho Cliente/Servidor (incluindo. portanto o GeneXus efetua a tarefa de definir as Unidades Lógicas de Trabalho (UTLs). antes das regras com evento de disparo AfterComplete. as transações e procedimentos são os únicos objetos (*) que permitem atualizar a base de dados. Em cada Transação: imediatamente antes das regras com evento de disparo AfterComplete. Onde o GeneXus inclui COMMIT exatamente? Em cada procedimento: ao final do programa fonte. temos um DBMS que assegura a integridade transacional. No objeto procedimento GeneXus incluiu um COMMIT automático no final do Source. GeneXus default o mesmos. 148 . No objeto transação GeneXus incluiu um COMMIT automático no final de cada instancia. É importante comentar que o GeneXus inclui a sentença COMMIT nos programas gerados associados a transações e procedimentos. é por default uma Unidade Lógica de Trabalho (UTL). mas o commit não é realizado automaticamente. haverá um COMMIT. Para cada interação completa que for efetuada em tempo de execução por meio da transação. os ambientes Web). e por GeneXus inclui nos programas gerados associados aos a sentença COMMIT. portanto. mas será visto que não realiza automaticamente um COMMIT.

149 . alterar o valor da Propriedade Commit on Exit para No.Personalização de UTL em GeneXus • Propriedade Commit on Exit de transações e procedimentos: Valores: • Yes (Default): COMMIT é executado • No: COMMIT Não é executado GeneXus oferece uma Propriedade para cada objeto transação e procedimento. O nome da Propriedade é Commit on Exit e seu valor por default é Yes (por isso. Se desejamos que certa transação ou procedimento não tenha COMMIT no programa gerado. para definir se deseja que seu programa gerado efetue ou não o COMMIT. toda transação e procedimento por default efetua COMMIT).

AfterUpdate. Isto é. e dos requerimentos. A Transação atualiza certos registros. assim que a chamada ao procedimento definir na Transação com um evento de disparo que ocorra antes da execução do COMMIT (dependendo se a transação tiver um nível ou mais. seja realizado todo o conjunto de atualizações ou nada na da base de dados). ____________________________________________________________________________ ¹ Em ambiente Web existe uma restrição importante: se uma transação chamar outra transação. Exemplo (mostrado acima): A Transação “X” chama um Procedimento “Y”. “Y” Commit on Exit = Yes Commit on Exit = No Importante: chamar a partir da Trn. e se deseja que esse conjunto total de operações. as chamadas que se requerem fazer. ou AfterLevel Level Atributo do 2do nível. “X” ao Proc. onde duas transações diferentes não podem ficar em uma mesma UTL. Por que motivo pode-se querer que não seja realizado COMMIT em uma Transação ou Procedimento? Para personalizar uma Unidade Lógica de Trabalho (UTL). e o procedimento outros. Não existe uma única solução para personalizar uma UTL. deverão ser efetuadas em momentos adequados. Para isto. ”Y” utilizando um evento de disparo que consideremos adequado e que ocorra antes da execução do COMMIT da Trn “X”. estejam em uma única Unidade de Trabalho Lógica (UTL). o Commit realizada por uma não aplica sobre os registros ingressados/modificados/eliminados pela outra. temos que configurar a propriedade Commit on Exit do procedimento com valor: No e deixar a propriedade Commit on Exit da Transação com o valor por default: Yes. e não por outra. 150 . para que seja executado ao final de todas as operações). e para ele o COMMIT deve efetuar na transação ao retornar do procedimento). podemos precisar ampliar uma Unidade de Trabalho Lógica (UTL). O fundamental é analisar qual objeto pode fazer COMMIT (podendo haver mais de uma possibilidade) e uma vez que se decida qual objeto efetuará COMMIT. podemos eliminar o COMMIT do procedimento. consista em uma única UTL (para assegurarmos que se ocorrer alguma falha. “X” call Proc. e deixar que seja realizado na Transação (ao retornar do procedimento para a Transação. Mas além disso.Personalização de UTL em GeneXus • Exemplo de Commit on Exit = No Trn. e deseja-se que ambos objetos estejam em única UTL. para que várias transações1 e/ou procedimentos. o Commit de cada transação contém somente “visibilidade” sobre os registros operados por essa transação. é fundamental que a chamada ao procedimento seja realizada antes que se execute o COMMIT na transação (já que a idéia é que ambos os objetos tenham uma única UTL. considerando se já executou o COMMIT ou não. Não poderá realizar-se personalização neste caso. ou BeforeComplete mas não AfterCompete). Isto é. poderia ser AfterInsert por exemplo.

Observar então que o commit não é pela transação inteira (ou seja. Concluindo. Por quê? Porque a transação realiza o rollback de tudo que foi efetuado depois do último commit. o COMMIT não será realizado na transação. ficaram gravadas as 29 anteriores (só não foi à trigésima). Outro Exemplo: A transação “Invoice“ estudada até o momento. Isto não é assim. Caso não modificarmos o valor predeterminado da propriedade Commit on Exit. foi perdido. não seria um erro . 151 . em um modelo de Protótipo cliente/servidor. poderíamos ter optado também pela alternativa de que não efetue COMMIT na transação (Commit on Exit = No). precisamos decidir qual objeto fará COMMIT e que as chamadas necessárias sejam feitas em momentos adequados. quando ocorre a queda do sistema na trigésima fatura informada. O cabeçalho da fatura 2 e as suas linhas informadas não estavam ainda “commitadas”. quais os registros que ficaram gravados na tabela e quais foram perdidos? A fatura 1 inteira estará gravada (cabeçalho e suas linhas). todas as interações do cabeçalho e suas linhas) e sim por cada instancia do cabeçalho e linhas. fazer dessa forma. foi efetuado um commit.Por Exemplo. Por quê? Porque ao terminar de inserir e passar a inserir a fatura 2. para que a transação e procedimento vistos conformem uma única UTL.chamar ao procedimento utilizando o evento de disparo AfterComplete. A fatura 2 com os registros que gravou até o momento que faltou energia. Linha da mesma ocorre um apagão. então se tivesse sido ingressados 29 faturas e o sistema caísse na trigésima. E o usuário executa a transação. Quando a energia volta e reinicializa a execução. já que ainda não foi realizado o commit). Depois insere a fatura 2 e quando inserir a 3era. mas no procedimento. todas as 29 faturas anteriores (todo o processo seria desfeito.como o é na solução anterior . inserindo a fatura 1 e todas as suas linhas. para que a UTL personalizada fique bem definida. mas sim que seja realizado pelo procedimento ao final de tudo. Se o commit acontece uma única vez antes da transação ser fechada.

porém não pode fazer um Commit dos registros inseridos por outra transação. Cada transação trabalha com diferentes UTLs. Se um programa chama uma transação Web. No segundo exemplo mostrado acima. as transações Web “vivem” somente o tempo em que o usuário de um navegador seleciona o link ou pressiona um botão e a nova página é mostrada. uma transação Web inicia uma UTL (Unidade Lógica de Trabalho) ao começar a executar e fecha-a (seja por COMMIT ou ROLLBACK) antes de terminar.. ou pelo procedimento em uma cadeia de chamadas.”Z” UTL Não podem ficar dentro de uma mesma UTL Em ambiente Web os registros “visíveis” para ser commitados por uma transação são os atualizados pela própria transação. onde a transação “X” chama a transação “Y” logo de ter inserido um registro.“X” UTL 1 • Trn. call call Trn. Toda modificação da base de dados que se faça durante a “vida” da transação deve ser confirmada ou eliminada antes que a transação Web finalize sua execução e retorne à página resultante. Não pode formar parte de outra UTL.. Não acontece isso com os procedimentos.”Y” UTL 2 Uma transação Web somente pode ter Commit dos registros inseridos por ela mesma. Este registro ficará “perdido”. porém não os de outra transação.”Y” (antes do Commit) Proc. e pelos procedimentos que esta chame antes do seu Commit. sem Commit. esta iniciará outra (nova) UTL. É por este motivo que no primeiro exemplo acima apresentado.“X” (depois do Commit) Trn. 152 . este Commit não valerá sobre o registro que teria sido ingressado previamente pela transação “X”. e pela própria transação.com tudo não podemos incluir a transação “X” na mesma UTL.Personalizaçã de UTL • Uma UTL composta por várias transações Web não pode ser definida call Trn. Internet trabalha de forma diferente. vemos que podemos formar uma UTL que envolva à transação “Y” e ao procedimento “Z”. Como conseqüência. embora a transação “Y” realize um Commit ao final do cabeçalho e linha são ingressadas.

voltaremos nele após estudar Business Components.Personalização de UTL • Se desejarmos ter uma mesma UTL para duas transações diferentes: Trn. pode-se usar as transações com Web Panels e Business Components. e utilizar o comando Commit.”Y” Solução: utilizar Business Components e o comando Commit após inserir variáveis Business Components dos registros associados a ambas transações (será visto mais adiante). Caso seja necessário que as operações de duas ou mais transações (com ou sem procedimentos incluídos) estejam em uma mesma UTL. Aqui simplesmente vamos deixar o tema sinalizado. onde vamos compreender esta solução. 153 .“X” Trn.

terá que executar o comando COMMIT ou ROLLBACK 154 .Comandos COMMIT e ROLLBACK de GeneXus • GeneXus oferece os comandos: COMMIT e ROLLBACK • Podem ser incluído em Procedimentos e Web Panels. e a todos eles se configura a propriedade Commit on exit = No… e no último procedimento se pergunta ao usuário se confirma. dependendo da resposta do usuário. assim como combinados com Business Components. • Exemplo (usuário final decide executar Commit ou Rollback): A partir de uma transação é chamado vários procedimentos consecutivos.

Objeto Procedimento 155 .

mediante o qual é possível listar informação na tela ou impressora. utilizando variáveis de tipo de dados business component. Procedimentos: Definem processos não interativos de consulta e atualização da base de dados. como as web panels. poderão ser realizadas atualizações incluso nos objetos que por natureza não oferecem esta possibilidade. existe um tipo de dados especial. Os procedimentos podem gerar um arquivo formato PDF. que não é estritamente um tipo de dados. Além disso. os procedimentos podem atualizar a base de datos1. Portanto. o business component. __________________________________________________________________________ veremos mais adiante.Procedimentos Definição • Processos não interativos de consulta e atualização da base de dados. 1 Como 156 . mas algo um pouco mais complexo. por meio do qual serão realizados atualizações a base de dados em qualquer objeto GeneXus.

já que qualquer alteração nas tabelas será gerenciado automaticamente pelo GeneXus e desta forma. utilizando para isso uma linguagem simples que contem comandos de controle. Por exemplo. Desta maneira obtemos uma real independência da base de dados. 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. etc. Desta forma. de acesso a base de dados.Características • Definição procedural • Definição sobre a base de conhecimento • Independência da base de dados: definição a nível de atributos 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. índices. para atualizar os programas alcança em grande parte das vezes. Somente mencionando os atributos que deseja acessar é suficiente para que o GeneXus determine esta informação. como regerar os objetos sem ter que modificar nada do programado neles. etc. nos procedimentos as especificações se realizam de forma procedural. Isto é possível porque GeneXus possui um completo conhecimento da estrutura da base de dados. 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. o analista não precisa explicitar estas relações na hora de recuperar dados. de impressão. A informação de como se calcula um atributo fórmula está contida na base de conhecimento. a seqüência de execução é determinada pelo analista. 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 explicitamente quais tabelas serão percorridas e nem mediante quais índices.). 157 . Também podemos utilizar o conceito de tabela estendida. já que GeneXus conhece as relações entre as tabelas da base de dados. sem necessidade do analista oferecer nenhuma outra informação. Isto nos permite utilizar automaticamente todo o conhecimento já incorporado ou gerado por GeneXus a partir das especificações realizadas.

__________________________________________________________________________________ 1 Não serão vistas no presente curso. para ser consultado pelos usuários em tempo de execução. Ver no Curso Não Presencial de GeneXus. Pode ter uma ajuda para cada linguagem. • Layout: Assim como as transações possuem uma tela (form). • Condições: Condições que devem cumprir os dados para ser recuperados (filtros). • Variáveis: Variáveis locais ao objeto. • Regras-Propriedades: Definem aspectos gerais do procedimento. arquivo. Nesta seção se define apresentação do procedimento: os dados que se quer listar e o formato da saída. parâmetros que recebe o objeto. descrição. Para cada procedimento se pode definir: • Source: Aqui se escreve o código correspondente a lógica do procedimento. como seu nome. • Documentação: Permite a inclusão de texto técnico. para o uso do procedimento. 158 . para ser utilizado como documentação do sistema. tipo de saída (impressora. variáveis podem ser definidas e são locais ao objeto. 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. os procedimentos possuem um “layout” de saída. etc. • Ajuda: Permite a inclusão de texto de ajuda.Elementos • Assim como nas transações. tela).

Os primeiros dois Printblocks ilustram no GeneXus tal qual as primeiras duas áreas pois contem unicamente textos. junto com o nome do país ao que pertence. devemos identificar na saída da listagem das distintas áreas que o compõem. Também poderíamos ter colocado estas duas áreas convertendo-as em uma e utilizando portanto um único Printblock. 159 . linhas. A cada uma delas a representaremos com um Printblock. Esta informação é a representada pelos atributos CustomerId. o terceiro Printblock conterá os três controles atributo CustomerId.Exemplo • Queremos implementar a listagem abaixo: área com dados fixos área com dados fixos área com dados variáveis (acesso a base de dados) Por exemplo. que representa informação que deve ser extraída da base de dados. vamos supor que queremos implementar um procedimento para imprimir o identificador. Transformando as áreas em Printblocks. CustomerName e CountryName da base de conhecimento da aplicação. O que queremos mostrar neste caso é o identificador e nome de cada cliente. Para isso. CustomerName e CountryName. O terceiro Printblock será o correspondente da área de dados variáveis da figura anterior. retângulos. o Layout do procedimento ficará como o da figura na página seguinte. nome e país de todos nossos clientes e queremos que a listagem saia como mostrada na figura.

cada Printblock deve ter um nome único para poder ser referenciado depois a partir do Source. No exemplo. 160 .: print header) 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. para listar todos os clientes. Esta estrutura repetitiva é o comando For each que estudaremos depois. Aqui simplesmente são declarados.Layout Nome de cada Printblock Printblock • • • • Sucessão de Printblocks Não importa a ordem de definição Cada Printblock deve ter um nome único Somente são declarados. A ordem que são executados fica determinado na seção Source que é a que contem a lógica do procedimento. Por esta razão. No exemplo anterior. o Printblock de nome “customer” deve ser chamado dentro de uma estrutura repetitiva no Source. são chamados a partir do Source com o comando “print” (Ex. A partir dali serão chamados mediante um comando específico para tal finalidade (o comando print). o mesmo procedimento teria sido impresso se houvesse especificado os Printblocks na ordem inversa (ou em qualquer ordem).

e que contem outros controles -atributos. e em cada caso terá os controles disponíveis segundo o tipo de objeto. tem a propriedade “Name”. o selecionamos e pressionamos F4 ou View/Properties.botão direito em qualquer lugar do layout e selecionamos Insert Printblock. muito importante visto que é o identificador do Printblock. retângulos. linhas. Para inserir os controles no Form de uma transação contamos com uma toolbox.-. 161 . sendo estes últimos os que efetivamente especificam qual é o que se quer mostrar na saída. A mesma toolbox se utiliza para inserir os controles no Layout. Com este identificador é que o Printblock pode ser chamado a partir do Source para ser impresso. De fato esta toolbox está disponível para todos os objetos GeneXus criados. que é inserido e eliminado do Layout pelo analista. Como todo controle. Em particular. Para inserir um Printblock . textos. etc.Layout: Printblock • Para definir os Printblocks temos os seguintes controles disponíveis: • e para inserir um Printblock – botão direito sobre o layout e escolhemos Insert Printblock O Printblock é um tipo de controle válido somente nos procedimentos. Para acessar as propriedades de um Printblock. o Printblock possui propriedades que podem ser configuradas pelo usuário.

chamar uma subrotina. comandos de controle para a execução condicional (if. Header. que são comuns a todos as linguagens de programação imperativa. do case). os comandos de atribuição e os de impressão. No final da sucessão de comandos que constitui o código geral ou principal do procedimento. 162 . exceto exceções. Do-case. For • Comandos de impressão: Print. Do Nesta seção se define a lógica do procedimento . para chamar a uma subrotina (do).: Exit. chamar outro objeto. Delete • Comandos para sair de um loop. para cortar as iterações dentro de um loop (exit) ou abandonar o programa (return). para acessar a base de dados (For each). Existem. podem definir-se subrotinas que podem ser chamadas (mediante o comando do) a partir do código geral. Depois serão tratados brevemente os comandos de controle. começamos estudando detalhadamente o comando de acesso a base de dados. Return. Call. para chamar a outro objeto (call). 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á. e consta de alguns comandos que veremos. for). Por sua importância. assim como também comandos específicos desta linguagem: para imprimir um Printblock do Layout (print). para inserir novos registros em uma tabela (new). fundamental na hora de recuperar a informação armazenada.Source • Define a lógica do procedimento mediante programação procedural • Linguagem simples • Comandos usuais de controle: If. a ordem em que serão executados. Não podem ser chamadas a partir de outro objeto (são locais). abandonar o programa. Do-while. Footer • Comando de acesso e atualização da BD: For each. etc. A linguagem utilizada para programar o código fonte dos procedimentos é muito simples. como em toda linguagem imperativa. o repetitivo (do while. New. etc.

Para cada registro dessa tabela. e GeneXus se encarrega de encontrar como fazer. Usando o For each se define a informação que vai acessar. • Com um For each se percorre uma tabela da base de dados: a tabela base do For each. com este comando se definem quais atributos são necessários em qual ordem vai ser recuperada. e em tais casos GeneXus dá uma série de mensagens de erro indicando por que não se podem relacionar os atributos envolvidos. • Para cada registro dessa tabela pode ser feito algo com a informação associada. ___________________________________________________________________________ 1 Quando estudarmos os business components veremos que utilizando seu método Load também se consegue consultar a base de dados. Portanto. (Exemplo: imprimir) • Todo comando For each termina com um Endfor A definição do acesso a base de dados para recuperar a informação se realiza com um único comando: o comando For each1. nem quais índices se devem utilizar para acessar a essas tabelas: isso GeneXus infere. Concretamente GeneXus sabe que com um For each se quer percorrer (ou navegar) uma tabela. Assim. se quer fazer algo com a informação associada (ex: imprimir).Comando For each • Utilizado para acessar a informação da base de dados. A esta tabela vamos chamar tabela base do For each. Quando aparece um For each se está indicando que se quer recuperar informação da base de dados. Evidentemente isto nem sempre é possível. Não se especifica de quais tabelas se devem obter. 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. 163 . A forma de o fazer é baseada em nomear os atributos a utilizar. todo comando For each possui uma tabela física associada: a tabela que será percorrida ou navegada.

nome e país de cada um dos clientes da base de dados. só o que fizemos foi For each do exemplo informar os atributos que nos interessava mostrar? 164 . Ou seja. imprimindo esta informação. e para cada cliente seja recuperado da tabela COUNTRY o nome do país ao qual pertence. queremos percorrer à tabela CUSTOMER.Comando For each • Exemplo: Listagem de clientes CUSTOMER • Layout: COUNTRY • Source: For each print customer Endfor Intuitivamente com este comando queremos listar identificador. (Observar que a tabela COUNTRY pertence à estendida de CUSTOMER) Como o GeneXus infere isto. junto com o identificador e nome do cliente.

já que o GeneXus conhece as relações entre as tabelas. como também do registro associado na tabela COUNTRY (que está na estendida de CUSTOMER).Comando For each • Tabela percorrida: CUSTOMER • Tabela acessada para cada cliente: COUNTRY CUSTOMER • INTERPRETAÇÃO: For each record in table CUSTOMER Find the corresponding CountryName in table COUNTRY print customer Endfor COUNTRY Dentro de todo For each navega-se . Não é necessário. mas podemos acessar as tabelas que constituem sua tabela estendida para recuperar a informação.percorre ou itera . não somente os dados de seu registro. e acessa “para cada” cliente. Dizemos então que se percorre CUSTOMER e se acessa além disso a de COUNTRY para buscar o resto da informação requerida. 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). A tabela base dessa estendida é escolhida como tabela base do For each. não apresentamos de forma explícita ao GeneXus esta informação. 165 . É por isso que no For each do exemplo. Como podemos ver claramente no exemplo apresentado. 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. a tabela base será CUSTOMER.

executando para cada registro o que for indicado nos comandos internos do For each.Comando For each: determinação de tabela base • O acesso a base de dados fica determinado pelos atributos que são utilizados dentro do comando For each. • Para esse conjunto de atributos. 166 . • Sua tabela base será a 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. GeneXus busca a mínima tabela estendida que os contenha.

CustomerName e CountryName. CountryName} ⊂ est(INVOICE) Mas: est(CUSTOMER) < est(INVOICE) est(CUSTOMER) é a mínima tabela estendida que contenha os atributos do For each. e recuperar o registro da mesma que cumpre: COUNTRY. Portanto.INVOICE como chave estrangeira (FK). se vamos percorrer seqüencialmente à tabela CUSTOMER. CustomerName. junto com o código e nome do cliente. Podemos ver o diagrama correspondente às tabelas nas quais aparecem os atributos do For each (Tools/Diagrams). . GeneXus conhece as relações entre as tabelas. CustomerName. A tabela estendida de INVOICE também contêm todos os atributos do For each. • CustomerName está somente em CUSTOMER (é um atributo secundário). 167 .CountryId e para o mesmo recupera-se o valor do atributo CountryName.CUSTOMER como chave primária (PK). e percebemos que eles são os contidos no print block de nome “customer”: CustomerId. 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). vamos acessar a tabela COUNTRY. Tabela base: CUSTOMER Para o exemplo apresentado onde queremos uma lista dos clientes: seu identificar.Comando For each: determinação de tabela base {CustomerId. • CountryName está somente em COUNTRY (é um atributo secundário).CountryId = CUSTOMER. nome e nome de país. para poder imprimi-lo. pois a de CUSTOMER também os contêm. e para cada registro dessa tabela. CountryName} ⊂ est(CUSTOMER) {CustomerId. mas não é mínima. Em que tabelas estão estes atributos? • CustomerId está em 2 tabelas: . observamos os atributos utilizados dentro do For each.

Esta listagem é muito útil para os relatórios. Neste caso se mostra somente a tabela COUNTRY. Estudando a listagem de navegação já têm a informação necessária para saber se está percorrendo a tabela esperada. até que chegue ao fim de tabela (utilizando o índice ICUSTOMER). Os filtros da navegação indicam que faixa da tabela base que vai ser percorrida. se aplicam filtros sobre os dados ou se devemos listar todos. 168 .Listagem de navegação tabela base A consulta é ordenada pela PK da tabela base Acessa para recuperar info relacionada (CountryName) tabela base: a navegada Listagem de navegação GeneXus oferece para todos os objetos uma lista conhecida como listagem de navegação. Também é mostrado num pequeno diagrama de tabelas. chave primária da tabela CUSTOMER. Desta maneira. qual é a tabela base do mesmo. Como pode ser visto. esta listagem mostra para o comando For each que aparece no Source. É por esta razão que no For each do Exemplo. GeneXus determinou que a ordem é realizado pelo atributo CustomerId. e em caso de que assim seja qual é esse índice (seu nome). qual é seu nome. e aparecem mais duas informações envolvidas: os filtros de navegação e o diagrama de tabelas. já que indica quais são as tabelas que são acessadas em cada For each do Source. que é o resultado da especificação do objeto. se existe um índice que satisfaça essa ordem. 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. etc. se existe um índice para recuperar os dados da tabela base. por que ordem essa consulta é resolvida (a ordem que os resultados são impressos). No Exemplo é percorrida toda a tabela base do For each: começando pelo primeiro registro de CUSTOMER. Neste caso GeneXus escolhe a ordem da chave primária da tabela base do For each. etc. a tabela base do For each com sua chave primária. 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. o analista não tem que executar o objeto para verificar se a lógica é a esperada. se estão aplicando corretamente os filtros desejados.

Se na listagem de clientes não queremos listar todos os clientes. 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. Cada condição booleana de um “where” pode estar composta de várias expressões booleanas concatenadas com os operadores lógicos and.For each: cláusulas Where • Permitem estabelecer filtros sobre os dados que serão recuperados . Observar que se &Start e &End estejam vazios. e sim. Se for vazia. • As cláusulas where são aplicadas somente se satisfizer as condições de suas cláusulas when (somente são válidas para arquitetura cliente/servidor). Com a cláusula where definida estamos dizendo ao GeneXus que não queremos todos os registros da tabela base. No exemplo. mas poderíamos ter programando o mesmo com duas cláusulas where. __________________________________________________________________________________ 1A través de um objeto que é pedido ao usuário. Exemplo: For each where CustomerName >= &Start when not &Start. No exemplo escrevemos uma cláusula somente where com uma condição composta. este filtro não será aplicado. Para restringir os dados que queremos listar no For each são utilizadas as cláusulas where do comando. Isto é lido da seguinte forma: o filtro estabelecido será aplicado pelo where somente quando satisfaça a condição do when. somente aqueles que satisfaçam a condição booleana da cláusula. Se interpreta da seguinte forma: os filtros estabelecidos pelo where são aplicados somente quando o when é satisfeito. e as carregar com valores fixos ou recebidos por parâmetro1. então devemos agregar ao For each que havíamos visto uma cláusula where. 169 . Igual é ao caso da segunda cláusula when. e portanto serão listados todos os clientes (como se não existissem os comandos where). como mostramos no slide acima. Observemos que no slide os comandos where estejam condicionadas com as claúsulas when. mas apenas aqueles cujo nome esteja dentro de uma faixa inserida pelo usuário.IsEmpty() where CustomerName <= &End when not &End. 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.IsEmpty() print customer Endfor • Somente para os registros que cumpram as condições booleanas das cláusulas where são executados os comandos internos ao For each. or e not. não serão aplicados nenhum dos comandos where. por exemplo um Web Panel. somente é aplicado o primeiro filtro: “CustomerName >= &Start” se a variável &Start não for vazia.

quando não tínhamos cláusulas where: os constraints (restrições).Listagem de navegação Listagem de navegação Aparece um novo elemento nesta listagem que não existia. utilizando o índice ICUSTOMER • 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. • que deve acessar a tabela COUNTRY cuja chave primária é CountryId para obter algum dado (CountryName) 170 . CustomerName. executar para esse cliente os comandos que aparecem dentro do For each. CountryName. Neste caso. Que informação ganhamos com esta listagem de navegação? • que a tabela base do For each continua sendo CUSTOMER • que a ordem correspondente da consulta continua sendo por CustomerId. imprime os valores dos atributos do Printblock “customer”: CustomerId.

os dados aparecerão ordenados pela chave primária da tabela base. CustomerId. No exemplo. Neste exemplo nada foi feito em relação à ordem. 171 . . a tabela base do For each é CUSTOMER. pelo identificador de cliente. que é da tabela COUNTRY. ou seja. estamos filtrando os dados a serem recuperados utilizando o atributo CountryName. pertencente à tabela estendida de CUSTOMER.For each: cláusulas Where • Atributos permitidos: os atributos da tabela estendida da tabela base do For each Exemplo: For each where CountryName = ‘Uruguay’ print customer Endfor Os atributos utilizados nas condições de filtro podem ser de qualquer tabela estendida do For each.

For each: cláusula Order
• Permite estabelecer a ordem que os dados serão recuperados. Exemplos:
For each order CustomerName print customer Endfor For each order CustomerName when not (&Start.IsEmpty() and &End.IsEmpty()) print customer Endfor

• Para determinar que a ordem seja descendente o atributo deve estar entre parênteses. Ex: order (CustomerName)

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).

172

Listagem de navegação

For each order CustomerName print customer Endfor

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)

173

OTIMIZAÇÃO: Ordem compatível com os filtros
For each where CustomerName >= &Start where CustomerName <= &End print customer Endfor For each order CustomerName where CustomerName >= &Start where CustomerName <= &End print customer Endfor Toda a tabela base é percorrida.

Não se percorre toda a tabela base: otimizado!

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

174

OTIMIZAÇÃO: Ordem compatível com os filtros
GeneXus sempre tenta encontrar a melhor ordem para que a consulta seja otimizável, isto é, coincida com algum índice definido na base de dados.

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.

175

Por exemplo, se temos as transações: COUNTRY { CountryId* } 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. CITY { CountryId* CityId* }

176

For each: cláusula Defined by
For each defined by InvoiceDate print customer Endfor • Não oferece funcionalidade alguma referente aos dados a serem recuperados. • Utilizada exclusivamente para ter um elemento a mais para a determinação da tabela base do For each desejado.
Exemplo: Mín. estendida que contenha CustomerId, CustomerName, CountryName: est(INVOICE) InvoiceDate,

tabela base INVOICE

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 print customer Endfor For each Defined by CountryName print customer 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.

177

For each: cláusula Defined by
• Atributos permitidos: podem aparecer vários atributos da tabela estendida, mas pelo menos um deve corresponder a tabela base desejada (caso contrário ocorre um erro). • Sugere-se que seja utilizado atributos secundários, visto que os mesmos estão em uma única tabela do modelo e isto evita ambigüidades.

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).

178

For each: cláusula When none
• Permite executar determinado código quando não encontrar nenhum registro no For each que cumpra as condições. • Exemplo: For each where CustomerName >= &Start where CustomerName <= &End
print customer

When none
print message

Endfor

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.

179

A justificatova para escrever cláusulas order condicionais. sendo atti um atributo da base de conhecimento escrito simples. . attn É uma lista de atributos. . ou entre parênteses.. então será melhor deixar uma ordem indefinida. …. Podem se mencionar atributos da tabela estendida. deriva se quisermos aplicar cláusulas where condicionais..] [defined by defined_attributes] [Blocking NumericExpression] code1 [when duplicate code2] [When none code3] Endfor A Sintaxe apresentada generaliza o exemplo com o que estamos trabalhando.parm2 [. se queremos filtrar por CustomerName > &Name when not &Name. Isto é. 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. Se nenhuma der true e existe uma cláusula incondicional (isto é.. ou ordem será indefinido. | [order none] [when condx]] [using DataSelectorName([[parm1 [. se vão avaliando suas condições (as do when) até a primeira que de True. por motivos de otimização das consultas.. Respondendo ao fato de que somente uma dessas cláusulas order tomará efeito. mas se não aplicar o filtro.] ])] [{where {conditioni when condi} | {attribute IN DataSelectorName([[parm1 [. que indica a ordem da consulta. Por exemplo. Quando um atributo do order aparece entre parênteses está indicando a ordem descendente para o mesmo.] ]} }.. querendo isto significa que dependerá da plataforma.Comando For each . pega essa ordem. sem when). e uma incondicional.. que deveria ser a última listada. Order order_attributes::= att1. Para isso especificamos a cláusula order condicional: order CustomerName when not &Name. visto que &Name está vazio. e com essa fica.Sintaxe For each [{[order] order_attributesi [when condi]}.IsEmpty().parm2 [. Se não existe tal cláusula.. e incluso poderá variar entre execuções sucessivas. 180 . É possível definir várias cláusulas order condicionais. então para otimizar a consulta deveríamos ordenar por CustomerName..IsEmpty() Ao invés do exemplo anterior.

code1 É uma sucessão de comandos que podem utilizar atributos da tabela estendida do For each.no Diagrama de Navegação.attp É um conjunto de atributos que serão utilizados somente efeitos de determinar a tabela base do For each. Using DataSelectorName Permite definir filtros de acordo ao critério definido no DataSelector1 definido em DataSelectorName. 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. ______________________________________________________________________________________________ 1 O objeto DataSelector será visto mais adiante no curso. Os atributos do order são levados em consideração na hora de determinar a tabela base do For each. or e not.…. o For each dará um error e o objeto que o contem não poderá ser gerado. primeiro se avalia a cláusula when de cada cláusula where. Poderia acontecer que estes atributos determinam tabela como a candidata a tabela base. etc. 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. 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ão os processados nos comandos internos ao For each (os do bloque de código code1). para um mesmo For each podem especificar-se n cláusulas where sucessivas. Como se desprende da sintaxe. 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. Ainda é o próprio DBMS que resolve o plano de acesso mais apropriado. 181 .. isto é. cada uma com uma condição: where cond1 where cond2 . att2. Ao mencionar aqui alguns atributos da tabela que se deseja percorrer. Os atributos que figurem neste bloque de código participam na determinação da tabela base do For each. Além disso. a informação antes mencionada influirá em sua determinação. Os atributos desta cláusula não determinam por si só a tabela base do For each. coincida com algum índice definido na base de dados. Desta maneira. Também se utiliza para melhorar o tempo de especificação em procedimentos complexos. e caso a condição seja cumprida. diferente da que seria determinada pelos atributos que aparecem no resto do For each (este caso tem sentido quando se estude “controle de corte”). Mas eles por si só não determinam. Where Condition Condição booleana que deverão cumprir os dados para ser processados dentro do For each. O leitor interessado pode recorrer as distintas fontes de documentação para estudá-la (Help. mas se depois os outros atributos do For each não estão contido na estendida dessa tabela.. Devem examinar-se também outras partes do For each.Escolha do índice: GeneXus escolhe automaticamente o índice que utilizará para satisfazer a ordem. 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. Para que uma restrição condicional possa ser gerada como tal. Da mesma forma que ocorre com a cláusula order. condições explícitas tanto no Where como nas Conditions) •A existência de índices sobre estes atributos. utilizando os operadores lógicos and.) Defined by defined_attributes::= att1. Release Notes. pode condicionar os filtros (com cláusulas when).’ . a condição do when tem que ser “avaliável" pelo DBMS que se está utilizando. podendo ser uma condição composta. GeneXus sempre tentará encontrar a melhor ordem possível para que a consulta seja otimizável. se gerar a mensagem de código spc0053 – ‘Unsupported conditional constraint”%1” changed to standard constraint %2. Não veremos esta cláusula. GeneXus tem que saber como escrever a condição na linguagem própria do DBMS utilizado. A este bloque de código o chamaremos corpo do For each. isto é. aplicam o filtro especificado no where. Wiki. Os atributos que apareçam na condição booleana podem ser tanto da tabela base do For each como da estendida. where condn A ocorrência de n cláusulas where é equivalente a ocorrência de uma única cláusula.

When Duplicate Esta cláusula tem sentido somente em procedimentos (já que trata de atualização) e será visto mais adiante. considerando os dados na ordem especificado. reduzindo assim o número de acesso a base de dados. 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.Os comandos especificados serão executados seqüencialmente para os dados da tabela estendida que cumpram as Condições de filtro. se o For each tem essa cláusula programada. Blocking Este tema será abordado mais adiante do curso. GeneXus utiliza o índice único para assegurar a unicidade dessa chave candidata e caso encontre duplicação. São considerados navegações independentes (code1. code2 e code3). mas a idéia geral é que a especificação desta clásula permite realizar atualizações e eliminações em blocos. executará seu código: code2. atualizar um atributo que é chave candidata (possui índice único) e já existir um registro com esse valor. Esta cláusula é executada se dentro do corpo do For each code1. não são inferidos nem joins nem filtros com respeito ao For each que o contêm (when none|when duplicate). 182 .

Comando For each • Podemos fazer que o GeneXus escreva o código do For each. a Toolbox nos mostra vários snippets que nos facilitam a escrita do comando For each. é 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) 183 . digitando simplesmente “fe” se escreve automaticamente 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. que nos ajudam a escrever o código fonte. inserindo “snippets” (menu Insert ou a partir do Toolbox): Os “code snippets” são moldes de código que GeneXus tem predefinido. que fazem que a escrita do código seja mais rápida todavia. A lista dos atalhos de cada snippet. Por exemplo. Quando estamos trabalhando no Source de um procedimento. Os snippets possui por sua vez um “atalho” (shorcut).

No exemplo. 184 . “invoices” e “bill” são dois Printblocks do Layout que contêm os atributos das tabelas INVOICE e BILL (recibo) respectivamente. Se um For each aparece no bloque de código code3. GeneXus suporta vários níveis de aninhamento para os For eachs. pode ser visto como For eachs aninhados porque um aparece dentro de outro. O primeiro percorre todas as faturas e o segundo todos os recibos. 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. Temos definido dois For eachs paralelos. dizemos que trata-se de For eachs aninhados. muda o comportamento. é igual a ter For eachs paralelos. Um For each “aninhado no when none” de outro. como aninhado a outro For each. Quando dentro do corpo do For each (code1) aparece outro For each. e portanto pode aparecer várias vezes dentro do Source. • As navegações são totalmente independentes O For each é um comando como outros. Exemplo: For each print invoice Endfor For each print bill Endfor • Também é utilizado quando um For each aparece dentro da cláusula When none ou when duplicate de outro.For eachs paralelos • Chamamos assim os casos dos For eachs que estão escritos de forma sequencial (não aninhada) . tanto em forma paralela (independente).

que permite recuperar muitos registros de uma tabela. para cada registro do principal. os dados de todas suas faturas. se queremos elaborar uma lista de todas as faturas do sistema. agrupar os registros de uma tabela segundo o valor de um atributo ou conjunto de atributos e para cada grupo. 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. é evidente que o que buscamos recuperar é. onde o primeiro navega pela tabela CUSTOMER e o segundo navega pela tabela INVOICE. Outro Exemplo é de uma lista de todos os clientes. For each . Endfor . sendo que imprimiremos detalhe de cada uma. • processar informação por grupos. recuperar alguns registros: os correspondentes ao grupo.. Por exemplo. e o faremos de uma forma bem simples.. isto é. 185 .... e sem que explicar tudo.. como veremos. onde para cada um se quer imprimir. • para cada registro de uma tabela recuperar todos de outra. O que o GeneXus detecta que se quer fazer com este tipo de estruturas. When none . Utilizando esta lógica é que o GeneXus infere as tabelas base e o comportamento dos For eachs aninhados. muitos registros do aninhado. devemos navegar por duas tabelas: INVOICE (que armazena os cabeçalhos) e INVOICEDETAIL (que armazena as linhas). sem colocar o nome das tabelas. Endfor Corpo do For each principal O For each é uma estrutura repetitiva. como veremos em seguida. Sempre a relação é um a muitos: para cada registro de uma tabela recuperar muitos da outra (podendose tratar da mesma tabela).. sabendo que o que desejamos é implementar alguma das três opções anteriores. Este comportamento se dá com um par de For eachs aninhados.For eachs aninhados • Para cada registro do For each principal se busca recuperar muitos registros do aninhado For each . Quando pensamos em For eachs aninhados.. recuperando somente as faturas desse cliente. além de seus dados pessoais.

onde a condição de filtro sobre os registros a serem somados ou contados ficava implícita. Podemos perceber o quão simples é esse processo. de maneira que só sejam impressas as linhas “dessa” fatura (lembrar que algo idêntico acontece com as fórmulas verticais. No Source programado. onde para cada uma se mostre tanto a informação do cabeçalho como das linhas. e aplica automaticamente a condição de filtro sobre os dados. percorremos à tabela INVOICE. Observemos que nem sequer tivemos que especificar a condição de filtro sobre os registros de INVOICEDETAIL a recuperar. imprimindo os atributos que nos interessam do cabeçalho e para cada registro dessa tabela. ProductPrice. InvoiceLineAmount} {InvoiceTotal} Se queremos realizar uma lista de todas as faturas do sistema.For eachs aninhados • Exemplo: imprimir todas as faturas com suas respectivas linhas For each print invoice_header For each print invoice_lines Endfor print invoice_total Endfor {InvoiceId. InvoiceLineQuantity. 186 . como InvoiceTotal. simplesmente utilizando os atributos que queremos usar. O GeneXus se dá conta da relação existente entre as tabelas. InvoiceDate. para imprimir os atributos que nos interessam de suas linhas. percorremos a tabela INVOICEDETAIL. e não precisa que especificá-la). CustomerName} {ProductDescription. ficando o GeneXus encarregado do resto.

pois. Aqui ficaremos com idéia intuitiva de que o faz de forma similar como o fazia no caso de um For each simples.InvoiceId Como para um For each simples. Encontra. 187 . E a partir dessa determinação.For eachs aninhados • Exemplo: imprimir todas as faturas com suas respectivas linhas INVOICE INVOICEDETAIL Para cada registro de INVOICE imprimir alguns de seus dados (InvoiceId.InvoiceId = INVOICE. utilizará a lógica correspondente. 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. Depois navega por INVOICEDETAIL e recupera os registros que correspondam a fatura que se está imprimindo. InvoiceDate) e de sua estendida (CustomerName). Os que cumpram a condição implícita: INVOICEDETAIL. o GeneXus deve determinar para cada For each (principal e aninhado) qual é sua tabela base. Mais adiante veremos com exatidão como é que o GeneXus determina cada tabela base. que deve percorrer as tabelas INVOICE e INVOICEDETAIL.

serão executados os comandos do corpo do mesmo. e essas serão as tabelas que se navegarão. 188 . respectivamente. Para cada registro da tabela base do For each principal. A partir da determinação das tabelas base de cada For each e das relações que encontre o GeneXus entre as tabelas envolvidas. Quando temos dois For eachs aninhados. como se pode pensar equivocadamente. que correspondem aos casos enunciados anteriormente: join. como qualquer outro comando. influencia a tabela base do For each principal. que será executado.GeneXus deve determinar a tabela base de cada um. no lugar onde estiver realizando uma navegação sobre sua tabela base.For eachs aninhados • GeneXus deve: • Determinar a tabela base de cada For each. Produto cartesiano e corte de controle. mas as determinações não são por completo independentes. surgem três possíveis casos de For eachs aninhados. Para a determinação da tabela base do For each aninhado. encontra-se o For each interno. • A lógica dos For eachs dependerá das relações encontradas entre as tabelas determinadas. Estudaremos cada um desses casos com exemplos. Entre esses comandos. • A partir disso se define as navegações que realizará para cada For each (existem 3 casos possíveis).

• A determinação da tabela base do For each principal. A tabela base de dita tabela estendida. depois do aninhado a este .. Em caso contrário. descartando os For eachs aninhados que este contenha (e todos seus atributos). onde estão incluídos ou dentro da tabela estendida previamente determinada (a do For each principal). Somente neste último caso de não se encontrar relações.. 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. se procede a determinar a tabela base como se fosse For eachs independentes. Neste caso consideram-se todos os atributos 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..For eachs aninhados: determinação das tabelas base Acontece de forma ordenada. 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.. intervêm unicamente os atributos do próprio For each: do order. de fora para dentro: primeiro se For each . GeneXus fixa os atributos utilizados dentro do corpo do mesmo. finalmente a escolhe. de um par de For eachs aninhados. where. e assim sucessivamente.. 189 . defined by e todos do corpo que não pertençam a um For each aninhado (tampouco intervêm os da cláusula When none). determinando For each cada vez a tabela base de um nível de encadeamento. será a tabela base do For each. • Para determinar da tabela base do for each aninhado. mas sempre busca a forma de encontrar relações entre ambas tabelas bases. Endfor Consideremos o caso mais simples. determina a tabela base do For each mais Endfor externo. Para cada For each.. Se não puder encontrar uma tabela estendida mínima que cumpra ambas condições. . When none .. é análoga ao caso de For each simples (sem aninhamentos).. Estudaremos um esquema resumindo o anterior depois. mas cumpre que contenha os atributos.

como os atributos que figuram não estejam contidos na tabela estendida de INVOICE (que é a tabela base do principal). e caso possível esteja reacionada com INVOICE. A tabela que cumpre ambos requisitos em INVOICEDETAIL. ProductPrice. InvoiceDate. InvoiceLineQuantity. InvoiceLineAmount} INVOICEDETAIL Para o exemplo apresentado anteriormente. 190 . mostramos acima como se determina cada tabela base. InvoiceLineQuantity e InvoiceLineAmount. ProductPrice. então se passa a determinar sua tabela base como se explicou anteriormente: se busca a tabela estendida mínima que contenha a ProductDescription.For eachs aninhados: determinação das tabelas base Tabela base For each externo For each print invoice_header For each print invoice_lines Endfor print invoice_total Endfor For each print invoice_header For each print invoice_lines Endfor print invoice_total Endfor {InvoiceId. Para a do aninhado. CustomerName} {InvoiceTotal} INVOICE Tabela base For each interno {ProductDescription.

os relacionados. já que a maioria das aplicações requerem navegações complexas sobre as tabelas.For eachs aninhados: lógica associada • Tabelas base distintas Fe externo 1 N Existe relação implícita que vincule o For each externo com um número N de registros do For each aninhado? Join: se recuperam alguns registros do Sim aninhado. (Caso 2) • Tabelas base iguais • Controle de Corte: Corresponde ao caso para recuperar informação por (Caso 3) grupos. Este tema é de vital importância. surgem os três casos de For eachs aninhados que foram mencionados e que estudaremos um a um em seguida. (Caso 1) ? Fe aninhado Não Produto cartesiano: se recuperam todos os registros do aninhado. Da determinação das tabelas base. 191 . onde se requer uma mistura de todos estes casos.

Também será indireta quando a tabela estendida do aninhado inclua a tabela base do principal. de forma a ficar somente com esses registros relacionados. CustomerName} {InvoiceId. relacionada com a primeira por uma relação N-1. InvoiceDate. Como encontra atributo em comum entre a tabela estendida do For each principal e a tabela base do aninhado1. Este é um dos casos mais comuns de For eachs aninhados. Ao encontrar esta relação. cai dentro desta categoria. O GeneXus encontra nesta relação. somente recupera os registros associados. -----------------------------------------------------------------------------------------------------------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. lista-se o mesmo. e a do segundo. Veremos exemplos em seguida. isto é. GeneXus encontra que tem N relacionados com ele. A relação será direta quando a tabela base do principal tenha relação 1-N com a tabela base do aninhado. na tabela base do For each aninhado. A tabela base do primeiro For each é CUSTOMER. e aí o nome “join” para este caso. InvoiceTotal} CustomerId INVOICE est(principal) ∩ base(aninhado) = {CustomerId} No For each aninhado é ordenado pelo atributo relação: CustomerId 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.Caso 1: Join • Distintas tabelas base mas existe uma relação 1-N direta ou indireta entre elas • Exemplo: Listagem de todos os clientes e suas faturas For each print customer For each print invoice Endfor Endfor CUSTOMER {CustomerId. O exemplo do procedimento que imprime todas as faturas do sistema. e na navegação interna. determina que esse atributo atue como condição de filtro na percorrida da tabela do For each aninhado. CustomerId. No exemplo apresentado acima ocorre o mesmo. 1 192 . junto com todas suas linhas da fatura. com seus detalhes. todos os registros de INVOICEDETAIL que estão relacionados com o registro de INVOICE que se está posicionado em cada interação. aplicará condições de filtro automáticas no For each aninhado. direta ou indiretamente. A relação será indireta quando isto não exista uma relação direta entre as tabelas base. e para cada registro da mesma. mas sim entre a tabela estendida do primeiro e a tabela base do segundo. Nesse caso tem uma relação 1-N direta entre as tabelas que se percorre: para cada cabeçalho da fatura. ou seja. seja superordinada desta última. onde se quer percorrer uma tabela. para cada registro da tabela base do For each principal. INVOICE. percorrer outra tabela.

GeneXus deve encontrar a tabela base do For each aninhado. os atributos internos a este For each. está otimizando automaticamente a consulta. Outro fato interessante que pode ser observado nesta lista: no For each aninhado não foi especificado a cláusula order. Observemos que estes atributos não pertencem a tabela estendida do principal. e a tabela base deste For each será CUSTOMER. que não explicitamos cláusula where no For each aninhado para filtrar as faturas do cliente do For each principal. que era CUSTOMER. InvoiceDate e InvoiceTotal. novamente. 193 . Desta maneira. como o GeneXus faz para determinar as tabelas base. Observemos. Depois. esta condição é aplicada implicitamente pelo GeneXus e pode ser visto na listagem de navegação acima. Esse caso é uma exceção a regra que fala que quando nenhuma cláusula order em um For each é especificada. Justamente. ou seja. Portanto.Caso 1: Join Vejamos. INVOICE será escolhida como tabela base do segundo For each. Os atributos utilizados no For each externo são CustomerId e CustomerName. CustomerId. não os do aninhado. 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. por tratar-se de tabelas relacionadas por uma relação 1-N direta. Os atributos que participam são InvoiceId. Observemos que somente participam na determinação desta tabela base os atributos do For each principal. GeneXus determina como ordem o atributo da chave primária da tabela base de dito For each. e é a mínima tabela estendida que os contenha. GeneXus não escolheu a ordem da chave primária da tabela base e sim pelo atributo da relação.

Isto pode ser visto claramente na listagem de navegação. O leitor pode testar este caso em GeneXus e estudar detalhadamente a listagem de navegação resultante. e o GeneXus a encontra. Neste caso. De fato.Caso 1: Join • Exemplo: Listagem de todas as faturas por país {CountryId. mas tem uma relação 1-N indireta. COUNTRY pertencem à tabela estendida de INVOICE. mas estão de forma indireta. para cada fatura pode-se encontrar somente um país relacionado à mesma. porque a tabela estendida do For each principal não tem intersecção com a tabela base do aninhado (est(COUNTRY) ∩ INVOICE = φ). a tabela base do For each principal está incluída na estendida do aninhado (COUNTRY ⊂ est(INVOICE)). Por este motivo. onde a informação que queremos listar está relacionada. mas existe uma relação 1-N indireta. Portanto. Observemos que elas não estão relacionadas diretamente. CountryName} For each print country For each print invoice Endfor Endfor base(principal) ⊂ est(aninhado) CountryId CUSTOMER CustomerId INVOICE COUNTRY {InvoiceId. InvoiceDate. que mostrará o filtro: “CountryId = CountryId” para o segundo For each. InvoiceTotal} COUNTRY ⊂ est(INVOICE) porque tem uma relação 1-N indireta condição implícita: todas as faturas do país são listadas Se queremos realizar uma listagem das faturas emitidas pelo país. 194 . não necessitamos especificar cláusula where no For each interno para filtrar as faturas do país do For each principal. Aqui queremos percorrer às tabelas COUNTRY e INVOICE. Este é um caso um pouco mais complexo que o anterior. mas desta vez como ‘Constraint’ visto que não pode otimizar a percorrida. teremos outro caso de For eachs aninhados com distintas tabelas base.

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. mas estes já não serão condições implícitas inferidas pelo GeneXus.Caso 2: Produto Cartesiano • Distintas tabelas base. est(principal) ∩ base(aninhado) = φe base(principal) ⊄ est(aninhado) 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. . O programador pode estabelecer filtros sobre os dados a recuperar. se recuperam todos os registros da tabela base do aninhado. 195 . realiza um produto cartesiano entre as tabelas. todos os produtos. se a tabela base de um For each foi COUNTRY e a do aninhado PRODUCT. mas sim especificadas explicitamente pelo programador. mas não existe relação 1-N direta nem indireta entre as mesmas. Por exemplo. • O resultado obtido é o produto cartesiano de ditas tabelas: para cada registro da tabela base do For each principal. ou seja. evidentemente não existirá relação e haverá um produto cartesiano e se percorre para cada país.

que apareçam listados clientes que não tenham faturas. devemos percorrer a tabela INVOICE ordenada por CustomerId. Desta forma processaremos a informação de um cliente. Para o registro apontado. (“print invoice”) b. para processar sua informação. Avançar o ponteiro ao seguinte registro e voltar ao passo 3. é porque está em uma fatura!.Caso 3: Controle de Corte • Exemplo: Para cada cliente que possui faturas. 196 . InvoiceDate e InvoiceTotal do registro apontado. Mas para poder agrupar as faturas por cliente. (quando se chega a este ponto. 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. pois se um cliente está nesta tabela. então a solução é acessar unicamente as faturas. o que acontece se um cliente não possuir faturas? Como a tabela base do For each principal é CUSTOMER. listar os clientes e suas faturas. reter o valor do atributo de corte ou agrupamento. 2. de tal forma de poder mostrá-las desse modo. No exemplo que vimos anteriormente. Voltar ao passo 1. o cliente sai impresso antes de saber-se se tem ou não faturas. da listagem de clientes e suas faturas. Se imaginamos um ponteiro que se vai mostrando sequencialmente pela tabela INVOICE. podemos escrever o pseudocódigo de nosso procedimento como segue: 1. e depois passaremos ao seguinte. é porque se chegou no final da tabela ou mudou o cliente). e assim sucessivamente. isto é. CustomerId. 4. Se não desejamos que isto ocorra. Acessar a tabela CUSTOMER (que está na estendida de INVOICE) para recuperar o CustomerName e imprimi-lo junto com o CustomerId (“print customer”) 3.

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. porque é ela que especifica por qual atributo ou conjunto de atributos o corte (ou agrupamento) será realizado. porque não especificála. Layout GeneXus oferece uma forma de programar o que foi visto de uma forma simples. Comparando este código com o que vimos anteriormente para o caso de join. Neste caso foi. 197 . 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. GeneXus determinaria como tabela base do For each principal CUSTOMER. mudamos radicalmente o comportamento. mas sim uma cláusula order. para ler somente a tabela INVOICE). a mesma que determinar para o aninhado). neste caso somente serão listados os clientes que possuem faturas. que será processada uma única vez (dentro do código do For each externo). junto com o defined by. Source For each order CustomerId defined by InvoiceDate print customer For each print invoices Endfor Endfor ordem determina o critério de corte Cada vez que muda o cliente é definido um grupo novo O “defined by” foi utilizado para que tabela base seja INVOICE e não CUSTOMER e assim implementar um controle de corte e não um join. especifica essa informação comum ao grupo.Caso 3: Controle de Corte • Exemplo: Para cada cliente que possui faturas. ambas cláusulas (order e defined by) são indispensáveis para que este relatório funcione como queremos. Somente com essas mudanças da lista original. Isto é. Neste caso. Não é em toda programação de controle de corte que deverá ter uma cláusula defined by no For each principal. e sim um corte de controle. vemos que existem somente duas diferenças: a cláusula order que aparece neste código. listar suas faturas. A cláusula order é indispensável. o resultado é outro. Se agregamos somente uma delas. como foi feito antes. A cláusula defined by não é indispensável em todos os casos. que não é o que queremos (pois não queremos implementar um join.

na ordem do segundo For each devemos mencionar o “segundo” atributo de corte e assim sucessivamente. mas agrupada por algum atributo ou conjunto de atributos. Um controle de corte é fácil de programar e pode ser feito seguindo as considerações anteriores. devemos mencionar o “primeiro” atributo de corte. Os controles de cortes podem ser simples. 198 . duplos.Caso 3: Controle de Corte Devem ser cumpridas as condições seguintes para implementar o Controle de Corte: 1. A seguir veremos um exemplo de um controle de corte duplo. etc. Quantos For each? Um a mais que a quantidade de cortes 4. Na ordem do For each mais extremo. Devemos estabelecer na cláusula order de cada For each externo. Não é obrigatório mencionar atributo/s na ordem do For each mais interno (em todos os demais For each é assim). For each aninhados 2. triplos. Mesma tabela base 3. É utilizado quando desejamos trabalhar com a informação de uma tabela. o atributo ou conjunto de atributos que queremos “cortar” (“agrupar”).

Determinação da tabela base de cada For each Como sempre. determinando de cada For each. Total 20 Total 40 15 Total 20 199 . Isto é. Exemplo: Customer: 1 João Silveira Date: 12/05/05 Invoice Total 1 15 Date: 01/01/06 Invoice Total 9 35 3 30 Customer: 3 Maria Silva Date: 06/06/05 Invoice 2 Date: 12/08/05 Invoice 4 8 Date: 02/02/06 Invoice 7 … Como agora queremos agrupar por cliente. sem levar em consideração os atributos dos For eachs internos ao que se está considerando. para cada data.Exemplo: Controle de corte duplo Vamos supor que queremos como antes listar os clientes e suas faturas. queremos mostrar. se começa de fora para dentro. 1. para cada cliente. as faturas existentes. 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. mas queremos agrupar as faturas de cada cliente por data. vamos seguir todos os passos que realiza GeneXus para inferir o comportamento do procedimento. e dentro desse grupo por data de fatura. para determinar as tabelas base de For eachs aninhados.

Como neste caso são três For eachs sobre a mesma tabela base. For each. For each Consideram os atributos dos lugares que estão em negrito e como todos eles estão incluídos na estendida do 1er. Determinação da navegação Depois de determinadas as tabelas base. agrupar por InvoiceDate. então teremos que ordenar o primeiro For each por CustomerId e ou imediatamente aninhado por InvoiceDate. duplo. For each Consideram os atributos dos lugares que estão em negrito e como todos eles estão incluídos na estendida do 2do. For each. quádruplo. Mínima tabela estendida que os contem: est(INVOICE) For each order CustomerId defined by InvoiceDate print customer For each order InvoiceDate print date For each print invoice Endfor Endfor Endfor Tabela base 2do. então se determina a mesma tabela base: INVOICE For each order CustomerId defined by InvoiceDate print customer For each order InvoiceDate print date For each print invoice Endfor Endfor Endfor Tabela base 3er. GeneXus determina a navegação. para todas as faturas com esse cliente. triplo.For each order CustomerId defined by InvoiceDate print customer For each order InvoiceDate print date For each print invoice Endfor Endfor Endfor Tabela base 1er. Lembremos que a cláusula order é fundamental para estabelecer o critério de corte em cada par de For eachs. seja simples. etc. For each Somente são considerados os atributos dos lugares que estão em negrito. Como em nosso caso queremos agrupar por CustomerId e depois. temos somente um ponteiro utilizado para avançar nos registros da tabela base. 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 (nro e total) Avançar o ponteiro ao seguinte registro 200 . Podemos pensar que quando falamos de controle de corte. então se determina a mesma tabela base: INVOICE 2. se trata de um controle de corte duplo.

Este resultado é claro se pensarmos que um único ponteiro vai se deslocando pela tabela base. Determinação da Tabela Base do For Each Externo Determina a partir dos atributos que aparecem dentro desse For each: cláusulas order. quando não tem um índice criado: o composto pela concatenação das ordens de cada For each com cláusula order. Se não encontra uma tabela estendida que contenha a todos os atributos do For each aninhado e que além desta relacionada. defined by e corpo do For each. determinando cada vez a tabela base de um nível aninhado. ou seja. buscando o melhor índice levando em consideração as condições explícitas ou implícitas do nível. vendo de fora para dentro: primeiro determina-se a tabela base do For each mais externo. 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. Verá que GeneXus escolhe uma única ordem. Como no caso de um For each simples. e fazer o mesmo que antes. 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.Recomendamos programar em GeneXus este procedimento e observar cautelosamente a listagem de navegação. no caso do For each principal ter esta cláusula. 201 . fica com a tabela estendida mínima que contenha os atributos ainda que não tenha relação. encontrar a mínima tabela estendida que contenha esses atributos. Mas não são For eachs independentes! Para o For each aninhado. exceto os atributos que estejam dentro do For each aninhado. Não participam os atributos que estão dentro do When none. que se encontra a mínima tabela estendida que contenha ditos atributos. Em caso afirmativo. se determina da seguinte maneira: busca a mínima tabela estendida que contenha a todos os atributos do For each aninhado. como se fosse um For each independente. 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. where. depois o que está aninhado a este e assim sucessivamente. Resumo: Determinação geral das tabelas Base Acontece de forma ordenada. tratando de encontrar aquela que tenha alguma relação com a tabela base do For each principal. Uma vez determinado a Order do Controle de Corte se otimiza.

. Pelo qual mostraremos alguns exemplos: For to step: • inicio. O valor de salto pode ser negativo e nesse caso irá decrementando a variável de interação em interação. senão especificarmos a cláusula step o incremento da variável será de um em um. por isso não incluímos a documentação deste tema. Exemplo For &i = 1 to 5 &ok = PInvoicing.. [case condn bloquen] otherwise bloquen+1 endcase for &var=inicio to fin [step salto] bloque Endfor for &var in Expression bloque Endfor Os comandos introduzidos são similares aos existentes nas linguagens de Programação imperativa conhecidas.Comandos de controle if cond bloque1 [else bloque2] endif do while cond bloque enddo do case case cond1 bloque1 [case cond2 bloque2] . Pode ser encontrada no curso não presencial ou no Help do GeneXus... 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.udp( &month ) Endfor __________________________________________________________________________ 1 As coleções representam listas de tamanho variável. De interação em interação a variável &var vai incrementando automaticamente numa quantidade igual a passo. incorporam alguns elementos importantes sobre administrar arrays e de coleções1 em GeneXus. O valor por default de salto é 1. Serão vistas quando estudarmos o tipo de dados estruturado (SDT).. até o valor fim que toma a mesma quantidade de interações. Os dois últimos. 202 .

é possível incluir comando que “corte” a percorrida. for &var in &collection . Endfor for &var in Procedure(parms) . 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)). vetor ou matriz. matrizes ou coleções. • Não é possível obter a posição da coleção/array/matriz durante a percorrida. Isto inclui o caso de que se chame uma Subrotina que também possui um For In Expression.. 203 . Isto significa que alterações no valor de &var no alcance da estrutura. vetor ou matriz na percorrida. •Igual que em um For Each ou um Do While. &e ) bloque &e += 1 enddo &x += 1 enddo Também pode ser uma variável coleção de qualquer tipo. não afetam ao correspondente valor da &collection o do &array(&x)..For in Expression: • Expression é qualquer expressão cujo valor seja uma coleção.. Se armazena na variável &var os valores de cada elemento da coleção. incluindo uma variável com a propriedade Collection em 'False' mas de um tipo de dados 'SDT collection' . endfor A expressão também pode não ser uma variável. 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. •Estas estruturas podem aninhar para percorrer vários arrays. ou de &array(&x.. vetor ou matriz. como Exit ou Return. para isto é necessário definir uma variável que atue como contador. endfor Considerações: • Não é possível modificar os valores da coleção. por exemplo no caso do resultado de um DataProvider ou de um Procedure: for &var in DataProvider(parms) ... • var é uma variável que deve ter o mesmo tipo de dados que os elementos de Expression.

Desta forma implementa-se a impressão na saída dos Printblocks do Layout. isto é. nome e país de cada um dos clientes de nosso sistema. visto que já vem instanciados. pois neste caso não é necessário acessar a base de dados para recuperar seus valores. não é correto escrever o comando print fora de um “For each” se o Printblock que desejamos imprimir contêm atributos. se queremos que em cada página da listagem apareça o cabeçalho: “CUSTOMERS REPORT”. então este comando pode ser utilizado em qualquer lugar do Source. Portanto. somente dentro do comando específico para ele. que permitem desenhar a saída do procedimento. Quando o Printblock que se quer imprimir não contêm atributos. Print Onde nomePrintBlock é o identificador de um Printblock do Layout. Não existindo no Layout um Printblock com esse nome. Se não for especificada. A única exceção desta regra se produz quando os atributos do Printblock estão incluídos entre os parâmetros recebidos pelo procedimento.Comandos de impressão • Print • Utilizado para imprimir a saída de um Printblock definido no Layout • Sintaxe: Print nomePrintBlock • Header • Utilizado para definir o que se quer imprimir como cabeçalho de cada página da listagem • Sintaxe: Header bloque end • Footer • Define as linhas de rodapé da página a ser impressa ao final de cada página do procedimento. então as páginas da listagem não terão cabeçalho. o comando For each. então é suficiente escrever no Source: Header Print title End Onde “title” é o nome de um Printblock do Layout que contem este texto. Este cabeçalho é opcional. ao tentar salvar o objeto mostra-se uma mensagem de error informando sobre esta situação. 204 . Exemplo: No procedimento que queríamos imprimir uma listagem com o código. Header Aqui se define o que se quer imprimir como cabeçalho de cada página da listagem. • Sintaxe: Footer bloque end Aqui veremos alguns comandos de impressão. Os atributos indicam acesso a base de dados e este acesso não pode ser realizado em qualquer lugar.

Os comandos do bloque de código são executados quando se chega ao final de uma página. mas neste caso. Exemplo: Footer print endOfPageText end onde endOfPageText é o nome de um Printblock do Layout 205 . somente sairá impresso este texto na primeira.Também poderíamos ter escrito diretamente: Print title no início do Source. como cabeçalho. sairá em cada uma das páginas. Footer Define as linhas no rodapé da página a ser impressas ao final de cada página do procedimento. se a listagem tem várias páginas. No outro caso.

Do contrario. passa a imprimir na próxima página (força um salto de página). O número de linhas que será impresso é o número especificado menos a margem de baixo (valor por default é 6). a saída do procedimento. Se o número de linha atual é maior ao número especificado.Desenho da saída Existem alguns comandos para desenhar efeitos da documentação. PL nlines: Seta o tamanho de página. a linha será impressa na próxima página. Caso não seja especificado um valor se assume o valor por default que é 0. Eject: Força a um salto de página. Apresentamos aqui alguns MT nlines: nlines é o número de linha em que se quer começar a imprimir a listagem. continua imprimindo na mesma página. ainda que somente 60 linhas sejam impressas no form. este comando as imprimirá na mesma linha. O de linhas começa na linha 0. Caso não seja especificado um valor se assume o valor por default que é 6. com uma margem inferior de 6 linhas. MB nlines: nlines é o número de linhas que se deseja deixar como margem inferior. Se o comando se encontra entre duas linhas. então. 206 . Lineno nlines: Define o número de linha onde vai ser impressa a seguinte linha. CP nlines: Se quiser na página atual um número de linhas maior ou igual ao número especificado. Noskip: Tem que estar imediatamente depois de um Printblock. Ex: PL 66 Seta o tamanho da página a 66 linhas.

‘PDF’) Em Web as listagens somente podem ser PDF e devem ser configuradas as propriedades e regras anteriores para que funcionem. 207 . web panel. O programa executável gerado pode compilar e executar de forma independente. e configurando a propriedade Main program do mesmo com valor True. Definição de um objeto como main Ao definir que um objeto é main (neste caso um procedimento. etc. A definição de um objeto como main se realiza editando as propriedades do objeto. ao selecionar Build / Run se verá como programa independente do Developer Menu e poderá compilar-se e executar-se. 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. mas poderia ser uma transação.). isto é.pdf’.Procedimentos PDF • Configurar as propriedades: • Main Program = True • Call Protocol = HTTP • Report Output = ‘Only to file’ • Regra • Output_file( ‘xx.

Condições • Permite especificar condições globais que devem ser cumpridas para que os dados sejam recuperados. então a mesma pode ser aplicada à este For each para filtrar os dados ficando unicamente com aqueles que satisfaçam tal condição.aquele ao que pertence -. estaremos filtrando os clientes. • Exemplo: 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 . 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 na tabela estendida de um For each encontra-se algum dos atributos que interferem numa “condição”. Se no Source do procedimento “PrintCustomers” temos: For each Print customer Endfor Então ao especificar as condições que se mostram no slide. 208 . as “condições” estão ligadas à todos os For each do Source que tenha sentido aplicá-las. de acordo com as condições (é equivalente ter as condições como “where”). E para que For eachs tem sentido aplicá-las? As Condições geralmente envolvem atributos.

209 . InvoiceTotal • “product” é um Printblock que contem os atributos ProductId. ProductStock Se o procedimento anterior tem definido as condições mostradas acima. somente tem sentido aplicar se utilizar CustomerName e não a outra. CustomerId. Isto é.Condições • Sendo o Source do procedimento é: For each Print customer Endfor For each Print invoice Endfor For each Print product Endfor For each where CustomerName>=&start Print customer Endfor For each where CustomerName>=&start where InvoiceId < 100 Print invoice Endfor For each Print product Endfor InvoiceId < 100. nesse momento as condições são examinadas para determinar a quais For eachs se aplicam e a quais não. Uma vez determinadas. InvoiceDate. Conditions: CustomerName >= &Start. Aplicam como filtro global por igualdade para os For eachs que tenha sentido. O mesmo ocorre com os atributos recebido como parâmetro. 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. Não tem sentido aplicar as condições neste For each já que não existe nenhuma relação. CustomerName. onde: • “customer” é um Printblock que contem os atributos CustomerId. ProductDescription. 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). as tabelas base dos For eachs que apareçam no Source se determinam sem olhar as “condições”. No primeiro. CountryName • “invoice” é um Printblock que contem os atributos InvoiceId. nem com identificador de fatura. o procedimento será equivalente a um que não tiver “condições” e com o Source que se mostra a direita. mas não participam na determinação das tabelas base. Na tabela estendida do último For each não se trabalha com nome de cliente. CustomerName.

3. Os filtros que ficam determinados ao receber atributos na regra parm são filtros por igualdade. Attn) Resumimos aqui as distintas formas de filtrar em um procedimento a informação da base de dados a ser recuperada: a. parm( att. São aplicados ASSIM que determinadas as tabelas base dos For eachs do Source. isto é. 210 . os filtros especificados nas cláusulas where de um For each ou nas condições podem ser expressões booleanas quaisquer.. 1.. se instanciarão unicamente os registros que tenham o mesmo valor que o recebido por parâmetro. incluso compostas. cláusulas where b. Por outro lado. As cláusulas where aplicam exclusivamente ao For each em que se encontram.. att ) Estudemos as diferenças e similaridades entre elas. isto é. 2.. para os For eachs que tenha sentido aplicá-los. enquanto que os filtros especificados como condições ou os que ficam determinados pelos atributos na regra parm são globais. aplicam a todos os For eachs do Source em que faça sentido aplicá-las.Filtros na navegação • Formas de filtrar os dados: • Cláusulas Where Participam na determinação da tabela base • Condições NÃO participam na determinação da tabela base • Regra Parm (Atributos recebidos como parâmetros) Exemplo: Parm(Att1 . .. os que aparecem nas condições ou na regra parm não o fazem. condições c. Enquanto que os atributos que aparecem nas cláusulas where participam na determinação da tabela base do For each onde se encontram.

Objeto Data Selector DS 211 .

com o objetivo de ser “referenciado” em diferentes consultas e cálculos. agrupados por sexo • Procedimento que aplica um desconto.Conceito • É um objeto GeneXus que permite armazenar um conjunto de ordens. que possui 3 valores: •Active •On Hold •Closed Os clientes ativos serão aqueles que tenham o valor Status. somente dos clientes ativos CRIAMOS O DATA SELECTOR COM DITO FILTRO (+ ORDER + DEFINED BY)… E O REFERENCIAMOS A PARTIR DOS LUGARES NECESSÁRIOS O atributo CustomerStatus está baseado em um domínio enumerado. defined by.Active. somente para clientes ativos • Web Panel que mostra o total de vendas por cliente. . permitindo assim reutilizar navegações Exemplo: Customer { CustomerId* CustomerName CustomerAddress CustomerGender CustomerStatus } Por exemplo: Em vários objetos. Status. se repete a necessidade de consultar os clientes ativos (CustomerStatus= “Active”) • Procedimento que imprime clientes ativos. filtros.Data Selectors .

Definição • Criar o objeto de tipo “Data Selector”. para serem usados em condições Conditions: Condições para filtrar os dados a serem recuperados Orders: Ordens condicionais (cada ordem com seus atributos separados por vírgula e when opcional) Defined by: Atributo ou lista de atributos que participam na definição da tabela base final . dar um nome e definir: A estrutura consta de: • • • • Parameters: Parâmetros recebidos a partir da “chamada” do Data Selector.Data Selectors .

ele pode ser referenciado em: • • • • Comandos For Each Grupos de Data Providers Fórmulas Aggregate Grids em Web Panels A forma de referenciar um Data Selector dependerá a partir de qual caso se deseja chamar. se deseja consultar os clientes ativos Exemplo: Customer { CustomerId* CustomerName CustomerAddress CustomerGender CustomerStatus } CustomerStatus= Status. Veremos a sintaxe para cada caso.): Em vários objetos de uma KB.Active Depois de definir um Data Selector.Exemplo Primeiro exemplo apresentado (Cont. .Data Selectors .

• Otimizam o funcionários.Data Selectors . • Facilitam a manutenção: A definição é alterada num único lugar e a alteração é aplicada automaticamente em todos os lugares da KB que forem utilizados.Benefícios • Economia e reutilização de código: A definição é feita uma vez e se reutiliza em várias consultas e cálculos na KB. conhecimento: Facilitam o treinamento dos novos .

Grid ou Fórmula: Com cláusula USING: intervém na determinação da tabela base.Data Selectors – Usos Em For Each… Duas maneiras de uso: • Com cláusula USING • Com operador IN na cláusula WHERE Importante: • Um Data Selector sempre tem tabela base. . os atributos presentes na definição do Data Selector intervém ou não na determinação da tabela base do For Each. Grupo. Com operador IN: não intervém na determinação da tabela base. • Dependendo da forma que for utilizado.

] ]) …… EndFor Exemplo 1: For Each USING ActiveCustomers() …… EndFor Exemplo 2: For Each USING ActiveCustomers() Where CountryName = "Uruguay" … EndFor For Each Where CustomerStatus = Status.parm2 [. todavia não mais por utilizar o conceito de Data Selectors.Active Where CountryName = "Uruguay" … EndFor ATRIBUTOS DO DATA SELECTOR PARTICIPAM NA DETERMINAÇÃO DA TABELA BASE DO FOR EACH Isto se Expande a: Nota: A performance será a mesma escrevendo 2 where no For Each que seja referenciado um Data Selector no For Each (que tem definida uma condição) + um where no For Each. . é: centralizar o conhecimento reutilizável em uma única definição e depois referenciar essa definição em todas as consultas e cálculos da KB que aplique.Data Selectors – Usos Em For Each… For Each com cláusula USING Sintaxe: For Each USING DataSelectorName([[parm1 [. . GeneXus sempre tratará de otimizar o código gerado.. já que seu objetivo como explicamos.

Data Selectors – Usos Em For Each… O atributo que antecede o operador IN deve pertencer a tabela estendida da tabela base do Data Selector For Each com operador IN (em cláusulas WHERE) Sintaxe: For Each Where <attribute> IN DataSelectorName([[parm1 [. filtrando os registros que contenham algum dos clientes da lista devolvido pelo Data Selector. INDEPENDENTE DO SELECT QUE SE GERA PARA O FOR EACH •ATRIBUTOS DO DATA SELECTOR NÃO PARTICIPAM NA DETERMINAÇÃO DA TABELA BASE DO FOR EACH TABLA BASE: INVOICE Neste exemplo: .A tabela base do Data Selector é: INVOICE .] ]) … EndFor For Each Where CustomerId IN InvoicesByDate(&FromDate. . .O For Each tem sua tabela base determinada pelos atributos incluídos no For Each e sem levar em consideração a informação armazenada no Data Selector.O atributo que antecede ao operador IN pertence a tabela estendida de INVOICE (CustomerId)… e a consulta associada ao Data Selector devolverá uma lista de valores correspondentes a dito atributo (devolve “uma lista de clientes” que tem faturas na faixa de datas dada). &ToDate) … CONSISTE NUMA CONSULTA A PARTE / INDEPENDENTE DO FOR EACH EndFor Exemplo: Definição do Data Selector “InvoicesByDate”: • É GERADO UM SELECT PARA O DATA SELECTOR. .O For Each navegará sua tabela base e estendida. ..parm2 [.

Variáveis somente podem estar envolvidas nas fórmulas locais . minimizada. na sintaxe das fórmulas Aggregate a expressão corresponde a expressão de busca.Unicamente para o caso de Count. Todavia tem que levar em consideração que: . maximizada. o resultado da Expressão deve ser um valor numérico .Para Sum e Average. variáveis.' <Parâmetro2> '.' <Parâmetro3>')'] Valor a ser devolvido caso não exista registros que cumpram com <CondiçãoAgg> • Exemplo: atributo fórmula quantidade de clientes ativos do país Considerações referente a sintaxe das fórmulas Aggregate: Como foi detalhado no slide. Pode ser um atributo (armazenado ou fórmula) ou bem uma expressão que envolve atributos. não vale uma Expressão e sim um atributo .' [<CondiçãoAgg>] '. somada ou média [<CondiçãoBusca] ['USING' <DataSelector> '(' <Parâmetro1> '. maximizada. constantes. minimizada. somada ou média.Data Selectors – Usos Em Fórmulas Aggregate… • É possível utilizar Data Selectors em fórmulas Aggregate tanto globais como locais • Sintaxe: NomeFormulaAggregate '(' <Expressão> '.' [<ValorDef>]')' Find | Max | Min | Sum | Count | Average Expressão de busca.

• Observar que na mesma definição de um Data Selector. .Data Selectors – Usos Considerações • Podem ser incluídos tanto variáveis como atributos nos parâmetros do Data Selector. ou não terá tabela base e outro comportamento dependendo de como seja “chamado” no contexto que for usado. terá tabela base e certo comportamento. • Incluir atributos implica que tenha um filtro por igualdade.

FÓRMULAS LOCAIS 221 .

eventos. etc.Fórmulas Locais Generalidades • Além de definir fórmulas associadas aos atributos (globais. no source de procedimentos. a nível da KB) também é possível definir fórmulas no próprio código • Chamamos neste caso de fórmulas: fórmulas inline ou fórmulas locais • É possível definir fórmulas inline = locais subrotinas. • O Comportamento depende: 1) Dentro do For Each 2) Fora do For Each 222 .

para filtrar por dito cálculo: For each order CountryId where Count(CustomerName)>50 … Endfor 223 .Fórmulas Locais Dentro do For Each • • Tabela base da fórmula = Tabela base do For Each É possível incluir na definição da fórmula: . DA FÓRMULA NA DETERMINAÇÃO DA TABELA BASE DO FOR EACH NÃO PARTICIPAM Outro exemplo de codificação possível é o que segue. na qual a fórmula é definida no próprio where do For Each.atributos da tabela base da fórmula + estendida .atributos da tabela navegada pela fórmula + estendida .variáveis • Exemplo: TABELA BASE FOR EACH = COUNTRY TABELA BASE FÓRMULA = COUNTRY TABELA NAVEGADA FÓRMULA = CUSTOMER ATRIBUTO EM COMUM: CountryId For Each order CountryId &NumberCustomers = Count(CustomerName) EndFor ATRIBUTOS QUE PERTENCEM NA DEF.

variáveis • Neste caso de uso. Então. e depois disso atribuir valores aos diferentes parâmetros envolvidos na definição da fórmula.atributos de tabela a ser navegada + tabela estendida . CustomerId = &CustomerId) endsub Consideração importante Uma fórmula se dispara quando começa o grupo que a contêm.Fórmulas Locais Fora do For Each • Se não estiver posicionado em nenhuma tabela no momento de disparo da fórmula não tem tabela associada a fórmula É possível incluir na definição da fórmula: . Se escrevermos o seguinte código: &CustomerId = 1 &total = Sum(InvoiceTotal. os valores dos parâmetros que serão levados em consideração não serão os que você atribuiu. os valores dos parâmetros serão aqueles que foram lidos quando o grupo foi executado na base de dados. CustomerId = &CustomerId) Solução: &CustomerId = 1 do ‘calctotal’ &CustomerId não tem valor sub ‘calctotal’ &total = Sum(InvoiceTotal. os itens aplicados são 1. e 4. O mesmo ocorre com as variáveis. 3. pelo contrário serão os lidos quando se executou o grupo que contem a fórmula na base de dados. Os valores das variáveis que são considerados no momento de disparar as fórmulas. se o grupo foi executado na base dados.Quando começa um programa . CustomerId = &CustomerId) 224 . Portanto: &CustomerId = 1 &total = Sum(InvoiceTotal. E quando os grupos são executados? .Depois de um Endfor Quando começa uma subrotina ou um evento Em particular como neste caso estamos explicando fórmulas locais definidas fora de comandos For Each.Quando começa um For Each . Isto significa que se possui uma fórmula definida com seus parâmetros em determinada linha de código. são os valores que as variáveis tem atribuído quando o grupo que contem a fórmula é executada. não tem filtros implícitos: For each defined by CustomerName &total=sum(InvoiceTotal) Endfor SOMA AS FATURAS FILTRANDO POR CLIENTE VERSUS &total=sum(InvoiceTotal) SOMA TODAS AS FATURAS • • Consideração importante: O disparo da fórmula é realizado no início do grupo onde se encontra.

225 .A variável &CustomerId não terá valor quando a fórmula é disparada. quando a fórmula é executada a variável &CustomerId terá valor 1. De tal maneira que com esta solução. e nesse momento a variável já está carregada com o valor desejado. CustomerId = &CustomerId) Endsub Já que assim obtemos um novo começo de grupo (quando a subrotina começa). Isto pode ser resolvido assim: &CustomerId = 1 do ‘calctotal’ Sub ‘calctotal’ &total = Sum(InvoiceTotal.

Tipos de dados estruturados SDT 226 .

Character. • Exemplo de Tipos de dados compostos (registros ou tipos de dados estruturados) Type Client = Record Name: Character(30) Depois são definidas as variáveis com este tipo de dados e se trabalha com elas.) • Tipos de dados compostos. Country: Character(20) City: Phones: Character(20) Record Home: Character(15) CellPhone: Character(15) end... end.SDT: Introdução • Linguagens de programação gerenciam: • Tipos de dados simples (Numeric. 227 . etc.

subestruturas e coleções: botão direito O editor de tipos de dados estruturados é similar ao editor de transações. Em particular ele também é um tipo de dados estruturado. pode selecionar e arrastar o atributo desde o Work With Attributes (janela editável da opção View do menu de GeneXus) ou inserir com o diálogo Insert/Attribute do menu de GeneXus. na qual se deve selecionar um tipo de dados simples. Observe que uma subestrutura é um membro composto. se mostra a janela que se vê a esquerda. Fazendo botão direito sobre um membro da estrutura. com o nome que identifica ao membro. ou uma subestrutura. Tip: Se desejar criar um SDT com exatamente a mesma estrutura que a de uma transação. subestruturas e coleções. ou um tipo de dados estruturado que já tenha sido definido na KB (propriedade Type somente adquire valor se estiver definindo um membro e não uma subestrutura ou coleção). Contem: Propriedade Name. Da mesma forma. se desejar que um membro da estrutura corresponda a um atributo. • SDT se compõe de: membros. um domínio. • Editor similar ao das estruturas de transações. Propriedade Type. ao invés de ser um simples. Propriedade Is Collection.SDT em GeneXus • São criados como qualquer outro objeto GeneXus. subestrutura ou coleção. então ao invés de definir um a um todos os membros. para indicar se o membro representa uma lista (em seguida veremos um exemplo). 228 . onde se pode inserir outro membro. basta arrastar (fazer Drag & Drop) o nome da transação desde o Folder View para a estrutura em edição do SDT.

quando se define uma coleção.SDT em GeneXus • Exemplo contendo coleção: Um país tem muitas cidades. e o de cada item da mesma.. Isto ocorre desta forma para que depois possa ser definido uma variável do tipo de dados do item. que corresponderá aos itens da coleção. para depois agregá-la para a coleção. onde é pedido dois nomes: o da coleção em si. Marcando o check box Is Collection se abrirá um ramo da estrutura como se poder. junto com o SDT se estará criando implicitamente outro. Como veremos em seguida. 229 ..

SDT: Utilização • São utilizadas através de variáveis. Este último é devido ao caso de poder querer definir uma variável somente desse tipo de dados. na coleção. para depois agregá-la com o método Add que já mencionaremos. &country Id Name Cities 1 Brasil • CityName CityName CityName Goiânia Santa Catarina São Paulo A direita pode se ver o diálogo de propriedades de uma variável &country que se está definindo dentro de algum objeto. 230 .City”. Observe que a variável &country foi definida do tipo de dados “country” que aparece na lista obtida ao fazer clique no combo box da propriedade “Data Type” do diálogo de definição de propriedades da variável. • Os atributos não podem ser definidos como SDT. O SDT Country definido na KB tal como se aprecia na página anterior. da lugar a criação de dois outros correspondentes aos itens da coleção “country.

.. Name Country City Phones Julia Silveira Brasil São Paulo Home CellPhone 555-155.Phones.33 &client. como propriedade variável.Country = ‘Brasil &client.City = ‘’São Paulo &client. &client. cada membro é acessado pelo nome.. 231 .Name = ‘Julia Silveira &client.Phones.44 092-155.CellPhone = .55..Home = .12.SDT: Utilização • Para dados não repetitivos.

SDT: Utilização • Exemplo: Transação que registra os recibos efetuados aos clientes e SDT baseado na transação: drag & drop Na proc.. é devolver toda essa informação em somente uma variável estruturada! parm( out: &bill). A outra opção. se carrega &bill com dados do recibo 7 da BD. Para isso se define um SDT baseado na transação Bill (os SDTs não podem ter o mesmo nome que uma transação. out: 232 .. Para não ter que ingressar um por um os membros do SDT com o mesmo nome que os atributos da transação.BillDate= BillDate &bill. Agregamos a nossa realidade uma transação de recibos. carregada como se mostra acima.BillInvoicePeriodEndDate = BillInvoicePeriodEndDate &bill.. razão pela qual a chamamos BILL_SDT). implementar o pedido. out: BillAmount). esse é um tema que veremos em breve.CustomerName = CustomerName &bill.. basta arrastar a transação Bill desde o Folder View. se lança um processo de faturamento. out: &bill) For each where BillId = 7 . e junto com a regra parm: parm( out: BillDate.CustomerId = CustomerId &bill. Vamos supor que uma vez no mês. out: CustomerName.da tabela BILL &bill. vamos supor que necessitamos um procedimento que devolva os dados de um recibo dado (por exemplo.BillInvoicePeriodStartDate = BillInvoicePeriodStartDate &bill. . o de id. out: CustomerId. Por agora. 7).. e se gera um recibo para o mesmo (autonumber). BillInvoicePeriodEndDate...BillAmount = BillAmount endfor Aqui se apresenta um exemplo com o qual continuaremos trabalhando. A geração do recibo será automática (será realizada pelo nosso sistema). dentro da estrutura do SDT e automaticamente se inicializará como se mostra acima. Uma opção é acessar mediante um for each a tabela BILL criada a partir da transação com o mesmo nome.. se escolhe período de faturamento (usualmente todo o mês anterior) se contabilizam todas as faturas efetuadas por cliente..poderia devolver: parm(. out: BillInvoicePeriodStartDate.

BillInvoicePeriodStartDate = BillInvoicePeriodStartDate &bill.. os que foram efetuados numa faixa de datas dado). &bill.BillDate = BillDate &bill.Add( &bill ) &bill = new Bill_SDT() endfor Vamos supor que queremos devolver uma lista de recibos (por exemplo.CustomerName = CustomerName &bill.CustomerId = CustomerId &bill.BillInvoicePeriodEndDate = BillInvoicePeriodEndDate &bill.SDT: Utilização • E se quisermos devolver uma lista de recibos? • Opção 1: não modificar o SDT e agregar a variável &bills coleção: For each where. 233 .BillAmount = BillAmount &bills..

&bill....BillInvoicePeriodStartDate = .Add( &bill ) &bill = new Bill_SDT() Baixo nível! Não existe outra forma? Tem que pedir novo espaço de memória para a variável &bill. de nível mais alto. &bill.... &bill new &bills.. para a seguinte iteração.. Como veremos em breve.BillInvoicePeriodEndDate = .BillDate= BillDate &bill. como agregar uma variável na coleção e pedir memória.. &bill.. &bill..SDT: Utilização &bills add &bill. existe um modo muito mais simples. DECLARATIVO.BillAmount = . de obter a coleção de SDTs carregada..CustomerName = . sem ter que nos preocuparmos em realizar as operações de baixo nível.CustomerId = . 234 .

Podemos pensá-lo como um procedimento especializado.este modo declarativo.... 235 ..SDT: Utilização em Data Provider Bills { Bill where . devolve info estruturada . que devolverá sempre informação estruturada (seja simples ou como coleção). { BillDate= BillDate CustomerId = CustomerId CustomerName = CustomerName BillInvoicePeriodStartDate = BillInvoicePeriodStartDate BillInvoicePeriodEndDate = BillInvoicePeriodEndDate BillAmount = BillAmount } } Data Provider: procedimento especializado. Aqui apresentamos o exemplo. que depois ampliaremos quando entrarmos de fato neste tema. de carregar uma coleção de SDTs se conhece com o nome de Data Provider. portanto de alto nível.

SDT: Utilização • Opção 2: modificar o SDT para que seja uma coleção e depois se trabalha da mesma forma. definindo as variáveis: &bills &bill 236 .

ou array de A É possível incluir comandos de “corte” da percorrida. Como pode ser facilmente inferido..ToString() ) msg( ‘Name:’ + &bill.CustomerName ) . Exemplo: A = SDT For &bill in &bills msg( &bill. não somente SDTs.. como exit ou return. 237 . para isto é necessário definir uma variável que atue como contador. se acessa a cada item mediante comando: For &var in expression code endfor &var: variável de tipo de dados A expression: expressão cujo tipo de dados é coleção de A. este comando é válido para coleções de qualquer tipo de dados. endfor A variável &var vai tomando os valores de cada posição da lista.Id.SDT: Utilização • Para dados repetitivos. Não é possível obter a posição do item durante percorrê-la. da mesma forma que em for each ou do while.

238 . Quando uma variável SDT collection é mostrada no form (como grid) se permite selecionar o item selecionado com o mouse como linha do grid.Count() &cVar.SDT: propriedades Os nomes dos membros de uma variável do tipo SDT collection são mostrados como propriedades: Além disso.CurrentItem() Retorna a quantidade de itens da coleção. para variáveis collection: &cVar. As propriedades Count e CurrentItem somente estão disponíveis para variáveis SDT Collection.

Elimina item que se encontre na posição especificada e corre um lugar todas as posições.FromXML( &xml ) &cVar. Alguns se aplicam a variáveis SDT não coleção.ToXml() Aqui se apresentam a maioria dos métodos de tipos de dados estruturados.Remove( Position ) &cVar.Clone() &var. se representam com &var. outros a coleções.SDT: operadores e métodos &var = new SDT() &cVar.Add( &item [. Ordena os elementos da coleção de acordo ao membro.Clone() A Carrega variável SDT a partir da string contendo uma estrutura xml. Position começa em 1.Clear() &var.Sort( memberName ) &var. Retorna referência ao elemento com posição relativa Position na collection.ToXml() Retorna uma nova referência ou ponteiro ao SDT especificado Agrega o item a coleção na posição relativa especificada. 239 . Elimina todos os itens da coleção Cria uma nova área de memória e copia os dados da variável nesta: &var1 = &var2. Se omitir é agregada ao final. assim como exemplos.Item( Position ) &cVar. Position]) &cVar. acessar ao wiki ou ao help da versão. Retorna uma string com o formato XML dos dados da variável SDT (que pode ser collection): ml = &var. Para a lista completa. se representam com &cVar.

55.44 </Home> <CellPhone> 092-155.12.44 092-155.33 &xml = &client.55.ToXml() <Client> <Name> Julia James </Name> <Country> Uruguay </Country> <City> Montevideo </City> <Phones> <Home> 555-155.33 </Home> </Phones> </Client> 240 .SDT: Exemplo • Método ToXml: Name Country City Phones Julia James Uruguay Montevideo Home CellPhone 555-155.12.

241 .SDT collection em FORM • Ao inserir num form uma variável SDT collection: aparece uma janela para selecionar os membros a serem inseridos que serão apresentados como grid e será carregado automaticamente : Pode selecionar-se do SDT os membros que se querem carregar como colunas do grid. BillInvoicePeriodStartDate e BillInvoicePeriodEndDate. Observe que em nosso caso temos omitido os membros CustomerId.

Objeto Data Provider DP 242 .

. cada um dos quais possui determinados dados).DP: Cenário • Troca de informação hierárquica entre aplicações ou dentro de uma mesma aplicação.. APPLICATION A Data Interchange APPLICATION B Sistema de Faturamento envio de info dos recibos Bill Id: Customer: Date: Amount: 2516 John Drotts 12/12/2008 1000 Sistema de Devedores/Credores Fa Bill Id: Customer: Date: Amount: 158 Dane Smith 12/12/2008 750 . uma listagem dos recibos correspondentes ao último faturamento. 243 . Se trata de informação hierárquica (a informação a ser enviada é a de recibos. XML é o formato mais usual de troca de informação hierárquica. ainda não sabemos o que vai acontecer no futuro neste aspecto (por exemplo se vai voltar a ser um formato comum ou formato Json). queremos enviar um sistema de devedores e credores. Vamos supor que a partir de nosso Billing System.

. aqui o chamaremos Bill). 244 .Procedimentos “procedurais” • Como obter os recibos para um faixa de datas informada? Utilizando um procedimento que receba a faixa de datas para o faturamento: &start e &end e devolva uma coleção de recibos: Bill for each using ActiveCustomers() &bill. e &bills uma variável collection do SDT Bill..BillDate = &today &bill.. in: &end. Observe que estamos utilizando o Data Selector ActiveCustomers para filtrar pelos clientes ativos e utilizando a fórmula inline sum. mas ainda não os registraremos na base de dados. ). endfor Tendo o mesmo SDT Bill que definimos quando estudamos os tipos de dados estruturados (ali o chamamos Bill SDT. quando estudarmos as formas de atualizar a informação da base de dados (aqui somente estamos obtendo a informação dos recibos. estamos utilizando um procedimento com os seguintes parâmetros: parm( in: &start.BillInvoicePeriodStartDate = &start &bill.Add( &bill ) &bill = new Bill () . out: &bills ). InvoiceDate>= &start and InvoiceDate <= &end and InvoicePendingFlag ) &bills. Este atributo será alterado a False uma vez que a fatura foi processada dentro do processo de geração de recibos que iniciamos aqui mas que completaremos mais adiante.BillAmount = sum( InvoiceAmount. sendo &start e &end variáveis de tipo Date que recebem a faixa de faturamento.BillInvoicePeriodEndDate = &end &bill.. onde unicamente somamos os totais daquelas faturas que pertencem ao cliente da atual iteração do For each e cujas datas se encontrem na faixa informada e tenham o valor True no atributo Booleano InvoicePendingFlag.CustomerName = CustomerName &bill.

como pode ser visto no exemplo. 245 . Desta forma o propósito do procedimento. que implementam o armado da coleção de recibos) • e com elementos de entrada. sua saída.BillInvoicePeriodEndDate = &end &bill. • com elementos de transformação (em nosso caso. Para realizar a Transformação possui outra linguagem (o código que podemos ver no exemplo) e depois para expressar o Output outro mais. que mescla: • elementos de saída. Para obter o Input tendo certa linguagem (em GeneXus se trata da base de dados. fica obscura dentro desse código. Pode se dizer que o foco está colocado na transformação. no caso dos procedimentos GeneXus. assim como também se obtêm os parâmetros). basta nomear os atributos..Add( &bill ) &bill = new Bill() endfor INPUT Transformation OUTPUT Situado dentro do código Qual o propósito do procedimento? Todo procedimento toma um Input. o comando for each. Como pode ver-se.BillInvoicePeriodStartDate = &start &bill. a direita das atribuições. tanto o Input como o Output se encontram situados dentro do próprio código de Transformação.BillDate = &today &bill.) &bills. o método add e o operador new.Procedimentos “procedurais” • Linguagem de Input • Linguagem de Transformação • Linguagem de Output Exemplo: For each using ActiveCustomers() &bill.BillAmount = sum( InvoiceAmount. obtêm um Output..CustomerName = CustomerName &bill. e mediante alguma transformação. .

. Portanto. 246 . Data Provider hierarchical structure Bills using ActiveCustomers() { Bill { BillDate = &today CustomerName = CustomerName BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount. BillAmount: 750 . Com um Data Provider. para cada elemento da estrutura hierárquica.. como se calcula.. BillAmount 1000 Bill BillDate: 12/12/08 CustomerName: Dane Smith ..Procedimentos “declarativos” • Linguagem de Input • Linguagem de Transformação • Linguagem de Output Transformation INPUT FORMAT OUTPUT TXT HTML XML JSON SDT .... Depois.. terá que indicar no Source do Data Provider... basta observar o lado esquerdo para deduzir qual será a estrutura resultante. é suficiente indicar o formato desejado para essa estrutura hierárquica resultante.) } } Propósito claro Bills Bill BillDate: 12/12/08 CustomerName: John Drotts . Depois. o foco está situado na linguagem de saída: observe que é indicado numa estrutura hierárquica do que é composto esse Output... .

. pode ser representada utilizando diferentes formatos existentes. Se num futuro aparecer um novo formato de representação de informação estruturada. </Bills> . <BillAmount>1000</BillAmount> Bill BillDate CustomerName .. BillAmount: 1000 Bill BillDate: 12/12/08 CustomerName: Dane Smith . 750 Bills </Bill> .. 247 . Depois..... GeneXus implementará o método de transformação para esse formato.. BillAmount: 750 <Bills> <Bill> <BillDate>12/12/08</BillDate> <CustomerName>John Drotts</CustomerName> . <BillAmount>750</BillAmount> Bill BillDate CustomerName . uma mesma informação estruturada. Data Provider hierarchical structure Bills Bill BillDate: 12/12/08 CustomerName: John Drotts . BillAmount 12/12/08 Dane Smith .... 1000 </Bill> <Bill> <BillDate>12/12/08</BillDate> <CustomerName>Dane Smith</CustomerName> .... e somente terá que utilizá-lo.. Essa é a idéia do Data Provider...... BillAmount 12/12/08 John Drotts ....Procedimentos “declarativos” • Linguagem de Input • Linguagem de Transformação • Linguagem de Output Transformation INPUT FORMAT OUTPUT TXT HTML XML JSON SDT . o Data Provider continuará sendo o mesmo.

.. 1000 OUTPUT .. BillAmount Bill BillDate CustomerName .. convertê-la ao formato XML.. 750 INPUT CustomerId 1542 CustomerName John Drotts Dane Smith . CustomerStatus A A ..... com o método toXml dos SDTs... com essa saída se realiza o desejado. DB 1543 . BillAmount 12/12/08 Dane Smith . invoices..Data Providers Estruturas hierárquicas em GeneXus? SDTs Bill BillDate CustomerName 12/12/08 John Drotts .. Surge a seguinte pergunta: Como em GeneXus representamos as estruturas hierárquicas de dados? A saída de um Data Provider será um SDT (ou uma coleção de SDTs).. 248 . não será da forma convencional (como parâmetro de out da regra parm)..... Vejamos como declaramos a saída. Depois. em particular. Até aqui fizemos uma análise descritiva...

. terá que declarar esse SDT na propriedade Output do Data Provider..Data Providers Bill BillDate CustomerName . veremos outra na página seguinte.... Mas não é a única possibilidade . que coincide com a estrutura que se infere do Source do Data Provider ‘GetBills’. collection. 1000 Bill BillDate CustomerName . 750 OUTPUT Aqui vemos para o exemplo que estamos estudando. BillAmount 12/12/08 John Drotts .. BillAmount 12/12/08 Dane Smith .. que tendo o SDT definido Bills. 249 .... onde terá sentido a propriedade Collection.

.. poderão ser especificadas tanto no grupo Bills. De todas as formas. e uma nova propriedade é aberta. mesmo não sendo requerido pode-se programar o Source da mesma forma que o anterior. isto é... BillAmount 12/12/08 Dane Smith . Collection Name..Data Providers Outra possibilidade (mesmo resultado): Bill BillDate CustomerName ... Bills. etc. Em seguida voltaremos nesse tema. 750 OUTPUT Se ao invés de ter o SDT collection Bills. com o grupo Bills iniciando a hierarquia. assim como os where que veremos em seguida.. Este Data Provider é equivalente ao anterior. Observe que neste caso não é necessário colocar a raiz da hierarquia.. } } Nota: a cláusula using. em casos como este. que permitirá dar nome para a coleção. o order. 250 . tivéssemos o que aparece acima.. que se infere a propriedade ‘Collection Name’. Bills { Bill using ActiveCustomers() { . como no grupo Bill. BillAmount 12/12/08 John Drotts . Bill. 1000 Bill BillDate CustomerName .. então. poderíamos programar o Source do Data Provider como vemos e depois configurar a propriedade Collection em ‘True’.

Todos estes inconvenientes são evitados com Data Provider. o resultado do Procedimento não acaba sendo de fácil visualização. como agregar um item a uma coleção com Add. mas sua desvantagem evidente era que necessitávamos implementar a forma de armar essas estruturas com operações de baixo nível. GeneXus tende a ser o mais declarativo possível e cada vez programar menos ‘procedural’. mais adaptável as mudanças. mais fácil de programar. 251 . mais independente de uma implementação particular.Data Provider • Objetivo: Retorno de dados estruturados. Assim mesmo. e pedir memória (new). Os Data Providers resolvem eficientemente um tipo de problema: aquele que consiste em retornar dados estruturados. razão pela qual ao olhar já se sabe a estrutura do Output. O foco aqui está na saída. para devolver dados estruturados vamos utilizar um DP ao invés de um Procedimento. GeneXus se encarrega disso. • Com Data Provider: facilidade de escrita e clareza. Para esse tipo de problemas contávamos com os procedimentos. se tivesse que fazer cálculos complexos para dar valor a cada membro da estrutura. os elementos de saída estariam incorporados no código. livre da forma que está implementada a carga do SDT. A forma declarativa tira do programador o problema e passa para a implementação da ferramenta. Quanto mais declarativo for uma ferramenta. • Com Procedimento: o SDT é feito com operações de baixo nível. É declarativo independe de implementação. menos o programador precisa resolver o problema: basta enunciá-lo. Quanto mais inteligente for ferramenta. Sendo declarativo.

. 252 . É a variável na qual se devolve o resultado...ToXml() Um Data Provider também pode receber parâmetros através da regra parm. mas se diferencia de um procedimento onde todos os parâmetros podem ser de entrada/saída. .... como também outro tipo.. Output: Bill Collection: True CollectionName: Bills Objeto GeneXus &TheBills = GetBills( par1. que também representa informação estruturada. a declaração do tipo de dados de saída se faz mediante as propriedades Output. in: parn. . . um procedimento que devolve informação estruturada é feito mediante uma variável que se carrega no código. de tipo de dados Bill. A chamada a partir de qualquer objeto GeneXus de um Data Provider é idêntica a chamada de um procedimento. Objeto GeneXus &TheBills = GetBills( par1. isto é. ser convertida ao formato desejado. e que deve declarar-se como de saída.. aqui somente poderão ser de entrada.. (e não a coleção Bills). com a estrutura hierárquica devolvida pode. por exemplo. Olhar esse tema para completar o conhecimento de Data Providers. não na regra parm. como XML.. parn) udp Data Provider ‘GetBills’ Parm( in: par1. com udp... Lembre que se o SDT definido na KB é o correspondente aos itens individuais: Bill. o Business Component. Por outro lado. A variável &TheBills deverá estar declarada no objeto GeneXus que se realiza a chamada. um Data Provider não somente pode retornar um SDT ou coleção de SDT. in: parn). parn) &xml = &TheBills. então a variável &TheBills será definida como Collection. se assume udp. Lembre que ao chamar um objeto e não especificar o método de chamada. no último parâmetro da regra parm. out: &bills ). Importante: Como veremos. Depois..Data Provider Utilização • Da mesma forma que um procedimento que devolve informação estruturada: Procedimento ‘GetBills’ Parm( in: par1. Em um Data Provider.

Se o SDT ter um membro collection de um item determinado. podemos omitir do Source o Item como grupo. GeneXus tem inteligência suficiente para matchear com o SDT. Tire uns instantes para pensar como deverá ser o SDT BillsInfo.. ) &quantity = &quantity + 1 } BillQuantity = &quantity } Com o mesmo resultado. . A esquerda o que apresentamos. ) &quantity = &quantity + 1 } } BillQuantity = &quantity } O exemplo que podemos ver aqui é parecido ao que trabalhamos. O Source não precisa ser escrito da mesma forma que a estrutura do SDT. para que se iguale com este Source. poderíamos ter escrito o Data Provider: Billsnfo { Bills { BillDate = &today CustomerName = CustomerName BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum (InvoiceAmount. 253 .. Exemplo: com o SDT que temos acima. .. Agregamos o elemento BillQuantity.Linguagem de DP • Componentes básicos: • Grupos • Elementos • Variáveis BillsInfo { Bills { Bill { BillDate = &today CustomerName = CustomerName BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount..

. • Pode ser repetitivo como pode não ser (ele tem inteligência para determinar). variáveis em um mesmo nível hierárquico.Linguagem de DP Grupos • Agrupam elementos. BillsInfo { Bills { Bill { … } } BillQuantity = &quantity } Será uma coleção de muitos BillsInfo { Bills { Bill { BillDate = &today CustomerName = CustomerName .. grupos. &quantity = &quantity +1 } } BillQuantity = &quantity } 254 .

não possui cláusulas associadas. podem ser associadas a este grupo. da mesma forma seria com tabela base. No exemplo que estamos trabalhando. Observe que o grupo de nome BillsInfo.. onde substitua os elementos da esquerda das atribuições por variáveis? Neste caso a presença de CustomerName a direita da segunda atribuição permite afirmar que tem tabela base: CUSTOMER. | [order none] [when condx]] [using DataSelectorName([[parm1 [.] [defined by att…] Bill { BillDate = &today CustomerName = CustomerName BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount. não será repetitivo. porque Bills será uma coleção de Bill.. filtros. . vamos fazer outra: e se for um for each..Linguagem de DP Grupos • Um grupo repetitivo é análogo a um for each: • Determina a tabela base (da mesma forma que num for each) • Tem disponível as mesmas cláusulas que um for each: BillsInfo { Bills { [{[order] order_attributesi [when condi]}. Por tanto o grupo será repetitivo.. o subgrupo Bill poderia ser omitido (somente deixar Bills) e que fique implícito. as cláusulas do grupo que permitem definir order.. iterando sobre a tabela CUSTOMER.. o grupo de nome Bill será repetitivo.] ])] [{where {conditioni when condi} | {attribute IN DataSelectorName([[parm1 [. defined by.. de forma diferente. Por que? Para responder a pergunta. Por este motivo.. . é um grupo que somente possui outro grupo. e os elementos que contêm estão definidos a base de variáveis e não de atributos: BillQuantity = &quantity &quantity =0 E o que acontece com o grupo Bills? Observe que neste caso..] ]} }.) &quantity = &quantity + 1 Ver mais adiante em opções avançadas } } BillQuantity = &quantity &quantity = 0 } No exemplo. temos a cláusula: Bill using ActiveCustomers() igual: For each using ActiveCustomers() se o atributo CustomerName não estivesse na segunda atribuição.. O grupo contido será repetitivo.parm2 [. . 255 . Deste modo.parm2 [. pela presença do atributo CustomerStatus no Data Selector ‘ActiveCustomers’.

seria aplicada para os dois subgrupos Client.Linguagem de DP Grupos • Grupos também podem ser repetidos: Clients { Client { Name = ‘Lou Reed’ Country = ‘United States’ City = ‘New York’ } Client where CountryName = ‘Mexico’ { Name = CustomerName Country = CountryName City = CityName O resultado retornado será uma coleção de N+1 itens: sendo N o número de clientes do México. Por isso é permitido que as cláusulas operem nos grupos repetitivos (itens). } } Se a condição estiver no grupo Clients. e não somente do grupo que é coleção de itens. 256 .

• Cada Elemento deve ser atribuído e sua sintaxe é igual a das fórmulas. } } 257 . False otherwise.Linguagem de DP Elementos • Um Elemento é um valor atômico no Output. Exemplo: Clients { Client { Name = CustomerName Active = True if CustomerStatus = Status.Active.

.. } } } 258 .Linguagem de DP Elementos • Elementos e Atributos usualmente possuem o mesmo nome notação mais compacta: Exemplo: BillsInfo { Bills { Bill { BillDate = &today CustomerName = CustomerName BillInvoicePeriodStartDate = &start .. } } } BillsInfo { Bills { Bill { BillDate = &today CustomerName BillInvoicePeriodStartDate = &start ..

. ) &quantity = &quantity + 1 } } BillQuantity = &quantity } 259 . .Linguagem de DP Variáveis • Algumas vezes é necessário realizar cálculos internos: Exemplo: BillsInfo { Bills { &quantity = 0 Bill { BillDate = &today CustomerName BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount..

gxtechnical. • Cláusulas de Paginação: Count e Skip • Para gerenciar quantos registros serão de saída. mas somente os seus elementos subordinados. • Cláusula NoOutput • em um Grupo significa que o grupo não deve estar presente na saída. http://wiki.Linguagem de DP Grupos: Opções avançadas • Cláusula Default (~ When none) • o grupo somente será de saída se o grupo precedente (com o mesmo nome) não estiver presente. • Cláusula OutputIfDetail • Para o grupo cabeçalho contendo grupo com suas linhas: somente se apresenta o primeiro de saída se tiver linhas. na página: http://wiki. • Cláusula Input • se necessita trabalhar com coleções (devolvidas por Procedimento ou Data Provider) como Input do DP.com/commwiki/servlet/hwiki?Data+Provider+Language 260 .com/commwiki/servlet/hwiki?Data+Provider+Language A informação completa desse tema em inglês pode ser encontrada em nossa comunidade wiki.gxtechnical.

7 Income = 0.3 } Tabela TAXES TaxInitialDate* TaxFinalDate* TaxVAT TaxIncome Não se inclui no Output se não encontrou registro no dia de hoje 261 .Linguagem de DP Grupos: cláusula Default • Cláusula Default: o grupo somente será de saída se o grupo precedente (com o mesmo nome) não estiver presente. (~ When none em for each) CurrentTaxes Where TaxInitialDate >= today() Where TaxFinalDate <= today() { VAT = TaxVAT Income = TaxIncome } CurrentTaxes [Default] { VAT = 0.

262 .Linguagem de DP Grupos: cláusulas de paginação • Count e Skip. Customers { Customer [Count = 20] [Skip = 100] { Code = CustomerId Name = CustomerName } } São omitidos os 100 primeiros clientes e são incluído no Output os 20 seguintes. • Para gerenciar quantos registros serão de saída.

Linguagem de DP Grupos: cláusula NoOutput • Em um Grupo significa que o grupo não deverá estar presente na saída: somente os seus elementos subordinados. </Employees> Employees { Employee { Id = EmployeeId Name = EmployeeName EarningInfo [NoOutput] Where IsAutorized(&UserId) { Salary = EmployeeSalary Bonus = EmployeeBonus } } } <Employees> <Employee> <Id>123</Id> <Name>John Doe</Name> <Salary>30000</Salary> <Bonus>5000</Bonus> </Employee> .. </Employees> …ao invés de… 263 .. <Employees> <Employee> <Id>123</Id> <Name>John Doe</Name> <EarningInfo> <Salary>30000</Salary> <Bonus>5000</Bonus> </EarningInfo> </Employee> ...

para cada registro de COUNTRY será carregada a informação de seus atributos CountryId e CountryName nos elementos Id e Name do item Country do SDT coleção “Countries” que estiver carregando. mas de forma intuitiva podemos pensar. e depois percorrerá a tabela CUSTOMER filtrando por aqueles registros para os quais CUSTOMER. no exemplo. se cada um deve acessar a base de dados. 264 .CountryId = COUNTRY. carregando para cada um os elementos Id e Name. A presença da cláusula OutputIfDetail faz que somente se apresentam na saída aqueles países que possuam clientes associados. e terá um join entre ambas tabelas na hora de recuperar a informação para carregar a coleção de países. de ter um par de grupos “aninhados” (um grupo que. entre outras coisas. contêm outro). Countries { Country [OutputIfDetail] { Id = CountryId Name = CountryName Customers { Id= CustomerId Name = CustomerName &quantity = &quantity + 1 } Quantity = &quantity } } Tabla base: COUNTRY Tabla base: CUSTOMER Se um país não possuir clientes associados não aparece como item da coleção Countries na saída. assim como o critério de navegação são determinados exatamente da mesma forma que no caso de um par de for eachs anhidados. então não será apresentado como item da coleção de saída.Linguagem de DP Grupos: cláusula OutputIfDetail • Cada item da coleção de saída tem um cabeçalho e algumas linhas: cláusula para o nível do grupo cabeçalho somente serão apresentados na saída aqueles grupos que tenham linhas. “Countries”. então as tabelas base. o grupo Country possui tabela base COUNTRY. Não mencionamos.CountryId. Isto é. o grupo Customers possui tabela base CUSTOMER. Se um país da base de dados não tiver nenhum cliente. Por esse motivo.

. que uma vez atribuídas são manipuladas de forma usual: &var = Proc. . parmn) &SdtVariable = DataProvider( parm1.udp( parm1... Por exemplo. . parmn ) • Mas se for necessário trabalhar com uma coleção é necessário utilizar a cláusula Input… 265 .. A forma mais clara de trabalho é através de variáveis... a saída de um Procedimento ou Data Provider.Linguagem de DP Cláusula Input • Até aqui assumimos que o Input vinha da BD. mas também é necessário outro tipo de entrada.

Name da linguagem procedural } } 266 .Code Similar ao ‘For &var in Expression’ Name = &Customer.Linguagem de DP Cláusula Input • Para trabalhar com coleções. VerySimple { Month Input &i = 1 to 12 { MonthNumber = &i } } Similar ao ‘For &i=1 to 12’ da linguagem procedural Outro Input pode ser um SDT collection: CustomersFromAnotherDataProvider { &CustomersSDT = GetCustomers() // a DataProvider that Outputs Customers collection Customer Input &Customer in &CustomersSDT { Id = &Customer.

Atualização da Base de Dados 267 .

Atualização BD
Insert-Update-Delete

• Atualização interativa:
• Transações: • Através do form o usuário ingressa/modifica/elimina os dados. • Vantagens:
• As regras de negócio são executadas (e não se atualiza registro que viole regra Error especificada) • Não se atualiza registro que viole integridade referencial.

• Business Components (BC)

• Atualização não interativa:
• Business Components (BC) • Procedures

Até aqui somente conhecemos uma forma de atualizar a base de dados de nossa aplicação: as transações. Como sabemos, uma transação determina a ou as tabelas requeridas para armazenar sua informação. Por sua vez, ao ser gerada, se converte no programa que implementa a lógica de inserção, eliminação e modificação de dados nessas tabelas, de forma totalmente transparente para o programador. Também a transação permite definir todas as regras de negócio que os dados associados deverão cumprir. O programa gerado se encarrega de executá-las. Assim, se em uma transação temos uma ou várias regras Error, que se disparam ao satisfazer determinadas condições, essas regras estarão incluídas no código gerado, e não se permitirá atualizar a base de dados até as condições que disparam essas regras deixarem de satisfazer para os dados que estão manipulando nessa oportunidade. Assim mesmo, como vimos, as transações asseguram o controle de integridade referencial, muito importante para assegurar a consistência da base de dados. Mas as transações não cobrem todas as necessidades referente a atualização de dados. Também será necessário uma forma não interativa, batch, para realizar atualizações sobre as tabelas. Para isso existem duas alternativas: atualização utilizando o que se conhece como Business Component, absolutamente relacionado com as transações, ou utilizar comandos específicos para tal fim dentro de objetos de tipo Procedure. Depois veremos que os Business Components permitem grande flexibilidade, visto que permitem atualizar a base de dados de qualquer forma: tanto interativa como não interativa. Em seguida introduziremos os Business Components e depois os comandos de atualização direta dentro dos Procedimentos.

268

Business Components
Cenário

• Necessitamos registrar os recibos que efetuamos aos nossos clientes.
autonumber
Regras: Default( BillDate, &today); Error( ‘The invoice period considered must be past’ ) if BillInvoicePeriodEndDate >= BillDate; Error( ‘Wrong invoice period’ ) if BillInvoicePeriodStartDate > BillInvoicePeriodEndDate;

Mas este é um caso que não nos serve a transação, visto que a geração de recibos é uma tarefa batch: se lança uma vez ao mês um processo que calcula e registra todos os recibos correspondentes as faturas dentro de determinado período.

269

Business Components
Cenário

• Já tínhamos declarado o Data Provider ‘GetBills’ que realizava o processo de geração de recibos desejado, mas não gravava:
Bill { BillDate = &today CustomerId BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount, InvoiceDate >= &start and InvoiceDate <= &end and InvoicePendingFlag ) }

parm( in: &start, in: &end); Output: Bill Collection: True Collection Name: Bills

E nos devolvia uma coleção de tipos de dados estruturados (SDT). Se observarmos, a estrutura hierárquica deste DP é quase idêntica a estrutura da transação Bill...

270

Business Components
Cenário

• ...e se pudéssemos guardar em uma estrutura os dados e depois gravá-los na base de dados?
Bill
BillDate CustomerId ... BillAmount 12/12/08 2516 ... 1000

For &bill in GetBills( &start, &end ) &bill.Save() endfor
Bills

Bill
BillDate CustomerId ... BillAmount 12/12/08 158 ... 750

e além de gravar, executar as mesmas regras que se executam quando se grava mediante a transação Bill, e controlando além disso a integridade referencial?

&bill não será uma variável de tipo SDT, mas sim Business Component!

271

Business Components
BC

• A partir de uma transação, pode-se criar Business Component (BC).
Permite encapsular a lógica da transação (regras, eventos, controles de integridade referencial, estrutura dos dados) de tal forma que possa realizar inserções, modificações e eliminações sem necessidade do form...

É criado automaticamente na KB um tipo de dados Business Component, que pode ser associado a variáveis, e cujo nome será o da transação.

Por default a propriedade Business Component estará apagada. Isso significará que a lógica de negócio dada pela transação, somente será utilizada dentro da própria transação, e não ao se criar um tipo de dados com o mesmo nome da transação, Bill, que permita encapsular a lógica da transação para utilizá-la a partir de outros objetos.

272

Business Components
Em qualquer objeto GeneXus (ex: um procedimento): A variável &bill terá a mesma estrutura que o SDT obtido a partir da transação, e se trabalha de forma análoga, mas além disso oferece métodos para atualizar a base de dados em função desses valores.

&bill.BillInvoicePeriodStartDate = #10-10-08# &bill.BillInvoicePeriodEndDate = #09-10-08# &bill.Save()

Será inserido registro na tabela BILL?

273

Business Components
Insert
O que acontece na transação se tentássemos gravar com estes dados?

&bill.CustomerId = 3456 &bill.BillInvoicePeriodStartDate = #10-10-08# &bill.BillInvoicePeriodEndDate = #09-10-08# &bill.Save()

Default( BillDate, &today); Error( ‘The invoice period considered must be past’ ) if BillInvoicePeriodEndDate > BillDate; Error( ‘Wrong invoice period’ ) if BillInvoicePeriodStartDate > BillInvoicePeriodEndDate;

Não será inserido!

10/10/08

>

09/10/08

Observe que se consideram alguns membros da estrutura da variável &bill, Business Component, e depois se executa o método Save (inexistente em SDTs). Isto é equivalente ao que ocorria de forma interativa se o usuário final insere esses mesmos valores nos atributos correspondentes do form da transação, e depois pressionar o botão ‘Confirm’. Portanto, da mesma forma que ocorre com a transação, deverão ser disparadas as regras e serem realizadas os controles de integridade referencial. O que acontecerá com esse conjunto de dados se tentar gravar mediante a transação? A gravação é impedida, devido que está cumprindo a condição da segunda regra de error. Por outro lado, se não existisse na tabela CUSTOMER um cliente com identificador 3456, a integridade referencial vai falhar e assim tampouco deixaria de ingressar o registro na tabela BILL da base de dados.

274

Business Components
Insert
E agora que os dados não violam regras e supondo que o cliente 3456 existe e &today>10/10/08? &bill.CustomerId = 3456 &bill.BillInvoicePeriodStartDate = #09-10-08# &bill.BillInvoicePeriodEndDate = #10-10-08# &bill.Save()

Será inserido registro na tabela BILL!

Com quais valores de BillId, BillDate e BillAmount?
BillId era autonumber... BillDate = &today... se dispara regra Default BillAmount vazio... não tem regra

e CustomerName?

Antes de executar o método Save do Business Component, o valor de BillId na estrutura de &bill será vazio. Portanto, uma vez que se execute o Save, como o atributo BillId era autonumber na tabela BILL, se executa a propriedade a nível da tabela e o registro será inserido com o número seguinte ao último dado. No caso de BillDate, da mesma forma, como não se atribui valor na estrutura de &bill, antes do Save estará vazio, mas quando este se execute, será disparada a lógica da transação, e em particular a regra Default( BillDate, &today ) declarada. Portanto no registro inserido na base de dados, o valor do atributo BillDate corresponderá a data de hoje. Para BillAmount poderíamos fazer a mesma análise. Mas a diferença do caso anterior, não tem regra que atribui valor, pela qual se insere o registro com valor vazio neste atributo. Se atribuir valor para &bill.CustomerName não será considerado na hora da inserção, visto que CustomerName é um atributo inferido, e não tem regra Update que permita modificá-lo. O mesmo acontece para atributos definidos a nível da estrutura da transação mas que foram fórmulas. Isto é, são atributos virtuais na transação, e também são a nível do Business Component. Seu valor é disparado.

275

CustomerId = 1258 &bill.Load( 100 ) &bill.Delete() Se realiza sempre e quando não exista nenhuma tabela que referencie ao Bill 100! 276 .Load( 100 ) &bill.BillDate = #06-01-08# &bill.Business Components Update-Delete E se o desejado é atualizar um registro.Save() Se atualiza o registro 100 da tabela BILL! (sempre que exista cliente 1258 e 06/01/08>=BillInvoicePeriodEndDate) E para eliminar o recibo 100? &bill. não inserir um registro novo? &bill.

Business Components Gerência de erros Em transações vemos os erros interativamente (e no Error Viewer). Load. um segundo parâmetro que define o Identificador da mensagem. "1". se tenha de cada mensagem.. <Id do mensaje>) Exemplos de <Id do mensaje>: "CustomerNameCannotBeEmpty". 277 . o Id é sempre em Inglês (independentemente do idioma selecionado no modelo). "Error1". etc..Success() E em caso de falha (por regra Error. falha de IR ou de duplicação) e/ou de regras Msg podemos obter a lista de mensagens de advertência ou de error: &messages = &bill.Save() Temos os métodos Booleanos: &bill.Load( 100 ) &bill. além da mensagem em si.BillDate = #06-01-08# &bill.. Check.CustomerId = 1258 &bill. O objetivo é que quando se execute a transação como Bussiness Component. Quando se executam os métodos: Save. "Error2" ou uma descrição como ser Se não especificar um identificador para a mensagem.Fail() &bill. Como nos inteiramos dos erros ou mensagens resultantes ao tentar atualizar via BC? &bill. e se obtenha a lista de mensagens ocorridas depois de executar uma ação sobre a base de dados. Delete se disparam e carregam as mensagens gerados automaticamente por GeneXus assim como as regras Msg e Error definidos na transação. sendo possível assim avaliar o identificador da mensagem para codificar o comportamento como conseqüência: Msg|Error(<mensaje>. Nota: Para as mensagens geradas automaticamente por GeneXus. enum Warning Error Para gerenciar os erros terá que definir uma variável de tipo de dados SDT pré-definido (vem com a KB) Messages (collection). seu identificador. As mensagens mais comuns geradas automaticamente por GeneXus são: As regras Msg e Error aceitam em sua definição além do parâmetro com a mensagem a mostrar. terá que perguntar pelo texto da mensagem. Se recomenda que sempre se recupere a lista destas mensagens e se faça uma “gerência de erros”. "2".GetMessages() de tipo prédefinido SDT.

InvoiceDate >= &start and InvoiceDate <= &end and InvoicePendingFlag ) Deixaremos pendente esta última parte para quando estudarmos. mas também um BC simples ou coleção. correspondente a os itens do SDT pré-definido Messages devolvido pelo método GetMessages do BC. para depois fazer uma operação de INSERT sobre a base de dados. as formas de atualização direta. Uma vez que obtemos e ingressamos na tabela BILL todos os recibos correspondentes ao faturamento. dentro de procedimentos exclusivamente. Lembremos que o valor deste atributo se utiliza para não processar duas vezes uma mesma fatura. umas páginas mais adiante. Isto é.. 278 . Observe por outro lado como foi definido a variável &message de tipo de dados Messages.. dos registros das tabelas. Aqui completaríamos o processo de geração de recibos. e modificar o valor de seu atributo InvoicePendingFlag. Observemos primeiramente um fato importante: um data provider não somente pode devolver um SDT simples ou coleção.Message. deveríamos percorrer as faturas consideradas. Não será possível fazer uma atualização ou eliminação com um BC carregado via Data Provider. um Data Provider somente permite satisfazer sua estrutura. passando-o para False.Business Components Caso de uso Data Provider tem como output uma coleção de Business Component Bill! Business Component omite valor da propriedade ‘Commit on Exit’ da transação: tem que utilizar comando Commit/Rollback de forma explícita! Necessitamos mudar para ‘False’ atributo InvoicePendingFlag de invoices faturados. Importante: o BC devolvido somente poderá inserir na base de dados. Lembremos que este valor se utiliza no Data Provider no cálculo do elemento BillAmount: sum( InvoiceAmount.

que armazenem nas variáveis correspondentes de tipo Date (&startDate e &endDate) e depois. a Web Panel. mostramos um objeto deste tipo em execução. se execute seu código. O utilizamos para pedir ao usuário final o período de faturamento A partir de uma Web Panel também pode ser utilizado &EndDate BC para atualizar a base de dados &StartDate Adiantamos aqui em apresentar outro tipo de objeto interativo que estudaremos um pouco mais adiante. 279 . Observe que o código é idêntico ao do procedimento visto antes.Business Components Outra opção Este objeto é do tipo Web Panel. quando o usuário pressione o botão associado ao Evento Enter da Web Panel. Com este exemplo pretendemos mostrar que mediante um Business Component pode se atualizar a base de dados a partir de qualquer objeto GeneXus. Sua função será pedir ao usuário final um par de valores.

Business Components Caso de uso interativo • Problema: inserir país somente se existir um cliente novo para o mesmo e não pode ficar país sem cliente no sistema. além disso. Como se insere um país e um cliente para o mesmo? O usuário deve executar a transação Country. Depois abrir a transação Customer. 280 . não deve ficar abaixo nenhuma circunstância ingressado um país sem pelo menos um cliente associado. Mas o que acontece se cair o sistema quando se está ingressando o cliente? Ficará o país ingressado (lembrar que cada transação por default faz commit ao final). é necessariamente devido a que se tem um novo cliente desse país. isto não se está controlando. Vamos supor que como requerimento. 1 3 se o sistema cair aqui? 2 commit automático 4 commit automático Lembremos que não se pode ter somente uma UTL com duas transações. ingressar o país. Então? Vamos supor que cada vez que se insere um novo país no sistema. Tal como temos implementada a aplicação. e ingressar os dados do cliente e confirmar.

.. &customer.Save() on AfterInsert. na continuação. GeneXus colocará controles para cada um dos membros da estrutura: &customer. As variáveis por default nas transações são de saída. as operações efetuadas por 2 transações não podem ser incluídas numa única UTL.CustomerName..Fail() on AfterInsert.CustomerId. o commit automático. &customer.CustomerAddress. Como? Dentro da transação Country. &customer. msg( ‘It fails’) if &customer. 281 . Portanto nas regras: &customer. Como temos visto.Save() on AfterInsert. O Save do customer deverá realizar-se necessariamente depois de inserir o país em sua tabela (do contrário a integridade referencial falha). 1 2 &customer. Umaa vez efetuado isto. Commit automático 3 Desvantagem: não são disparadas de forma interativa as regras associadas a Customer. Sabemos que neste momento o registro correspondente ao país já terá sido gravado..CountryId = CountryId on AfterInsert. necessitaremos fazer a inserção dentro da mesma transação. terá que especificar regra Accept para que possam ser escritas em execução e o possa ingressar valores para as mesmas.Business Components Caso de uso interativo • Solução: na transação Country. simplesmente inserindo no form a variável (da mesma forma que acontecia com um SDT). Por esta razão. teremos previamente que ter setado a propriedade Business Component da transação Customer. de tal maneira que se crie este tipo de dados na KB). etc. e depois neste Save. criar variável &customer de tipo BC Customer e inseri-la no Form e agregar a regra Accept. de tipo business component Customer (para isso. definimos uma variável &customer. Necessitamos que a inserção do país na tabela COUNTRY e a inserção do cliente na tabela CUSTOMER se realizam dentro de uma mesma UTL.

.. • A partir de outra Transação (da mesma forma que uma variável podia de forma interativa inseri-la no Form. • Reutilização de código (as regras de negócio não precisam ser duplicadas) • Vários objetos GeneXus podem atualizar a BD.Business Components Resumo • Objetivo: • Reutilizar a lógica do negócio definida nas transações. Web Panels. Usar o poder das transações (sem seus forms) desde outros objetos GeneXus: • Procedimentos. também um BC) • Benefícios: • Atualização na BD garantindo integridade dos dados e execução das regras do negócio. 282 .

não quando a atualização é realizada através da própria transação.. Analogicamente. NoPrompt.. Se quiser qualificar de uma só vez um conjunto de regras: [BC] { regra1. Exemplo: [BC] Default( BillDate. existem qualificadores para indicar que uma regra somente se execute se estiver correndo a transação com seu form web: [WEB]. } O mesmo vale para eventos. Se existe uma regra que chama um objeto que possui interface. form. mas somente quando se executa o Business Component associado: é qualificando a regra com [BC]. . regran. 283 . &today). Default_mode. etc • Eventos: todos os eventos da transação são ignorados. exceto os eventos Start e After TRN (e eles também são ignorados se incluírem referências a objetos com user interface). isto é. Existe uma forma de especificar que uma regra declarada na transação não seja aplicada quando se executa a transação. prompt.Business Components Regras e Eventos • Regras: são executadas todas as regras da transação exceto (são ignoradas pelo especificador): • as que incluem user interface ( Ex: Customer. regra2.call()) • as que não aplicam: parm. Nota: quando falamos “são ignorados” nos referimos no contexto da atualização utilizando BC. essa regra não é incluída no BC.

Atualização não interativa direta Procedimentos 284 .

filtrando por InvoiceDate. O exemplo que apresentamos completa o que havíamos iniciado a respeito ao processo de geração de recibos. ou de sua estendida. ao receber no atributo CustomerId.Procedimentos Update • Não tem um comando específico para modificar um registro: se realiza de forma implícita dentro do comando For each. in: &EndDate). podendo estes pertencer tanto a própria tabela base como a tabela estendida. Aqui poderiam atualizar-se não somente esse atributo. e dentro do mesmo o comando de atribuição Podem ser realizadas várias atualizações dentro do mesmo For each. se atualiza o valor do atributo InvoicePendingFlag. para cada fatura que cumpre as condições. Observe que aqui se está percorrendo a tabela INVOICE. mas qualquer da própria tabela INVOICE. com as exceções indicadas na continuação. Exemplo: parm( in: CustomerId. in: &StartDate. A modificação de dados da base de dados se realiza em forma implícita: não tem um comando específico de atualização. 285 . por InvoicePendingFlag. que é foreing key. Dentro do for each. Para atualizar um ou vários atributos de uma tabela se utiliza o comando For each. se ordena por este atributo para otimizar). assim como por CustomerId (na listagem de navegação se observa que mesmo não tendo sido especificado order.

bloque1 [when duplicate bloque2.quando se chega ao Endfor para cada iteração. não permite fazer a atualização. Se desejar tomar uma ação no caso disso ocorrer. isto é. não se atualiza. Todavia poderíamos querer atualizar um atributo que não está definido como chave primária. e existe o valor duplicado.. para cada instancia da tabela base. existindo a cláusula when duplicate seu código é executado. caso encontre duplicado. Como vimos antes. • A integridade referencial não é controlada. o comando For each agrega a cláusula when duplicate.. deve controlar-se que não se dupliquem seus valores. 286 . Exceto: • os que formam parte da chave primária da tabela base. • Se atualizar um atributo que é FK não se controla existência. está definido como chave candidata (mediante um índice unique). mas sim depois que se encontram todos. Somente tem sentido se existe alguma chave candidata para esse For each. • A atualização se realiza no Endfor. • os que formam parte do índice pelo qual se está acessando a tabela.Procedimentos Update • Atributos atualizáveis: os da tabela estendida do For each. For each . não podemos atualizar dentro do comando For each atributos da chave primária.. Em que momento ocorre efetivamente a atualização dos registros envolvidos? A atualização não ocorre quando encontra um comando de atribuição dentro do For each. Se o atributo é chave candidata....] Endfor • Somente se realiza controle de duplicados: Se dentro do for each tentar atualizar um atributo que tem definido um índice unique. Vamos supor que temos o seguinte diagrama de Bachman genérico: A* B C D B* E F E no Source de um procedimento fazemos: For each C = &C E = &E D = &D Endfor Aqui a tabela base do For each será claramente a de chave primária A e dentro do For each estamos atualizando tanto atributos da própria tabela base como da estendida.

287 . Não será o caso de nosso exemplo. onde N é o número que se estabelece na cláusula Blocking. for each where InvoiceDate >= &StartDate where InvoiceDate <= &EndDate Blocking 1000 InvoicePendingFlag = False endfor Até a N-ésima (1000) iteração. Com a N-ésima se envia comando: Update massivo na BD e se atualizam os dados do buffer. Ao invés de interagir com o DBMS em cada operação de atualização. realizando um comando UPDATE individual de BD. saltará o error de duplicados e se iterará sobre o grupo. um por um.Procedimentos Update • Eficiência: Se tiver um milhão de registros para serem atualizados? Para cada um se envia um comando UPDATE ao servidor de BD (que não tem por que estar na mesma máquina que o Web Server) eficiência? for each where InvoiceDate >= &StartDate where InvoiceDate <= &EndDate InvoicePendingFlag = False endfor • Atualização massiva: cláusula Blocking reduz número de acessos a BD. o Update se realiza em um buffer. ao enviar ao BD o comando UPDATE do grupo. mas o que aconteceria se estiver fazendo uma atualização massiva que inclui algum atributo chave candidata da tabela. uma vez chegado o buffer com as 1000 atualizações. Realizar um “blocking” nas operações de atualização da BD significa armazená-las em memória e enviá-las em grupo ao DBMS. a interação tem lugar somente cada N operações de atualização. e se encontram duplicados para alguns dos registros do grupo de 1000 que se está processando? Nesse caso.

convêm agregar cláusula Blocking com um fator de bloqueo. O comando Delete elimina o registro que estiver posicionado no momento dado. Para eliminar dados se utiliza o comando Delete dentro do comando For each. É por isso. Não controla a Integridade Referencial Exemplo: For each defined by InvoiceDate Blocking 1000 Delete Endfor Elimina todos os registros da tabela base: INVOICE. podemos programar um procedimento: For each where InvoiceDate <=&date For each defined by InvoiceDetailQuantity DELETE // se eliminam as linhas Endfor DELETE //depois de eliminar as linhas se elimina o cabeçalho Endfor Para uma eliminação mais eficiente. Por exemplo. Elimina o registro da tabela base em que estiver posicionado. Sei desejamos eliminar todas as faturas anteriores a uma data informada. se agregar “Blocking 1000” a eliminação física não é realizada em cada iteração.Procedimentos Delete • • • • • Para eliminar registros de uma tabela: Comando Delete. Deve estar dentro de um comando For each. 288 . Somente se eliminam os registros da tabela base. eliminando-os em grupos de 1000 (para fazê-lo de forma mais eficiente). mas sim a cada 1000 vezes que se chegue ao Endfor. adequado. Se executa assim que encontra o comando (e não no Endfor). não da estendida. dependendo do número de registros da base de dados. se eliminarão o grupo de 1000 registros em um único acesso a Base de Dados (ao invés de 1000). cuja tabela base seja a tabela que se quer eliminar registros. que não pode aparecer “solto” dentro do Source. N. Deve ir dentro de um For each.

Se programar a cláusula when duplicate. não se realizará a inserção. Se não colocamos o For each não se realizará a atualização do preço para esse registro. Este deve criar um novo registro na tabela PRODUCTPRICELIST. também se controla e não se realizará a inserção. Se quiser inserir um registro para o qual exista chave candidata duplicada. É determinada a partir dos atributos que aparecem dentro do comando new. ProductPriceListDate e ProductPriceListPrice. onde se dá valor aos atributos da tabela que se quer inserir o registro. Para isso se utiliza o comando new que escrevemos acima. para a data correspondente ao dia em que se executa o procedimento. Procedimento “NewPrice” New ProductId ProductPriceListDate ProductPriceListPrice endnew = &ProductId = &today = &price • Realiza o controle de duplicados: Se já existe o registro para o produto e data? atualizar o preço: cláusula when duplicate. deve determinar a tabela na qual se realizará a inserção (tabela base do new). é o de duplicados. O único controle que realiza. sendo sua chave primária composta.Procedimentos Insert • Comando New: permite inserir um registro em uma tabela. a atribuição deve estar dentro de um comando For each. se executa. Observemos que para realizar a atualização do atributo. se atualiza o registro encontrado. é como se não tivesse incluído cláusula when duplicate. isto é. Observemos que dentro do mesmo aparecem comandos de atribuição. conformada por ProductId e ProductPriceListDate. se existir um registro com os valores de ProductId e ProductPriceListDate. New ProductId = &ProductId ProductPriceListDate = &today ProductPriceListPrice = &price when duplicate for each ProductPriceListPrice = &price endfor endnew Vamos supor que queremos implementar um procedimento que faça o seguinte: para o produto cujo código é recebido por parâmetro. insere um novo preço (também recebido por parâmetro) em sua lista de preços. Em nosso caso. que está composta pelos atributos ProductId. Em caso de existir cláusula when duplicate. Cada vez que GeneXus encontra um new. 289 . do lado esquerdo numa atribuição.

devido que a chave primária é autonumber. dispomos da cláusula blocking para ir guardando em um buffer e depois fazer a inserção de todos os registros uma vez. como as inserções vão sendo realizadas no buffer até chegar a 1000. Em nosso caso não falhará a inserção. Se as inserções são muitas. assim como vimos para o caso das atualizações. e que não temos chaves candidatas (através de índices unique) na tabela de recibos (BILL). ali se pode falhar alguma inserção. um por um. Se são milhares de clientes. pode otimizar a inserção e fazer em blocos O caso mais comum será ter o comando new dentro de um for each. não é possível até completar o buffer saber se alguma operação falhará. For each using ActiveCustomers() New Blocking 1000 BillDate = &Today BillInvoicePeriodStartDate = &start BillInvoicePeriodEndDate = &end BillAmount = sum( InvoiceAmount. Se existe cláusula When duplicate no New. 290 . então pelos registros que falhem. Quando se executa o INSERT massivo da base de dados. executando o INSERT simples. Nesse caso. Qual alternativa você escolheria? Lembre que com os comandos de atualização dentro de procedimentos. Mas se não for o caso. o único controle que será realizado é o de duplicados. poderíamos realizá-lo com um procedimento que utilize o comando new de inserção. InvoiceDate >= &start and InvoiceDate <= &end and InvoicePendingFlag ) Endnew endfor No for each se percorrem os clientes ativos e o new insere na tabela BILL um recibo novo para esse cliente (por que CustomerId não aparece atribuído?).Procedimentos Insert • Exemplo: se quisermos realizar a geração de recibos diretamente em um procedimento (não através de BC). se executa a cláusula. O mesmo processo de geração de recibos que havíamos resolvido anteriormente utilizando Data Provider e Business Component. visto quem em geral se quer inserir registros na base e cálculos efetuados em função de outros. se itera nos elementos do buffer.

em bloque_asignaciones2 se realizam tais atribuições. como não pode inserir o registro porque já existe um. não faz nada e segue adiante com o próximo comando. bloque_asignaciones1 é um bloque de código composto na sua maioria por sucessivos comandos de atribuição (aqui se atribui valor aos atributos da tabela na que vai inserir o registro. devem pertencer a uma tabela física tabela base Nota: Não é necessário atribuir valor a todos e cada um dos atributos da tabela. não é necessário atribuir valor para o registro a ser inserido (pegam do contexto). de tal maneira que não se permite inserir um registro que já exista na tabela..…. O comando new realiza um controle de duplicados. For each). podem também atribuir-se valores a variáveis). attxm = . attN attx1 = . A cláusula when duplicate do comando permite programar a ação em caso de que o registro já exista na tabela base (tanto por chave primária como por chave candidata). Para isso. como vimos. A cláusula Defined By opcional. No caso de que o comando new esteja dentro de uma cláusula repetitiva (ex. Isto é. se incorpora os mesmos efeitos que no comando For each: ajudar a determinar a tabela base. ao ocorrer o que acabamos de falar.Procedimentos Insert • Sintaxe do new new [ Defined by att1. Alguns vem instanciados pelo contexto do new (ex: se está dentro de um for each). é possível reduzir o número de acessos a base de dados usando a cláusula blocking. 291 .…. Na sintaxe apresentada. mas como o que se faz é atualizar um registro (e não inserir um novo). as atualizações somente podem ser realizadas dentro de um For each. Normalmente. se o registro que se quer inserir se encontra duplicado não se realizará nenhuma ação e a execução continuará no comando seguinte.. se quer atualizar alguns dos atributos de dito registro... attN ] [ Blocking NumericExpression ] bloque_asignaciones1 [ when duplicate For each bloque_asignaciones2 Endfor ] endnew att1.. estas atribuições aparecem entre “For each – Endfor”. . A tabela base do new se obtêm dos atributos do Defined By e os que apareçam do lado esquerdo de atribuições dentro do bloque_asignaciones1.. Aqui não se utiliza a tabela estendida. Se a cláusula when duplicate para um new não for especificada.

Um exemplo discutível é o que utilizamos para alterar o valor do atributo InvoicePendingFlag a False. não envolvia integridade referencial. sabendo que milhares de faturas deverão ser atualizadas. o que não ocorre nas transações (em um Business Component). + • O único controle que se realiza é o de duplicados. nem duplicados e podia envolver milhares de registros. • Se controlam duplicados. Fica claro da numeração mostrada acima que os Business Components oferecem todas as garantias e constituirão a forma de atualização privilegiada. • Não tem nenhuma relação com transação aqui não tem regras. Nos procedimentos o único controle de integridade que se realiza automaticamente é o controle de duplicados. - • Atualização via comandos em procedimentos: • Não se realiza controle de integridade referencial.InvoicePendingFlag = False &invoice. Qual seria a alternativa? Prender a propriedade Business Component da transação Invoice. • Se disparam as regras do negócio. e no procedimento MarkInvoiceAsNotPending definir variável &invoice com esse tipo de dados e depois: for each where InvoiceDate >= &startDate where InvoiceDate <= &endDate where InvoicePendingFlag &invoice.Load ( InvoiceId) &invoice. 292 .Atualização BD BC versus Proc • Atualização via Business Component: • Se realizam controles de integridade referencial.Save() endfor Mas esta solução será mais ineficiente que a atualização direta utilizando “blocking factor”. Não havia nenhuma regra que o implicara. Cabe perguntar-se então: quando atualizar utilizando estes comandos? A resposta é: quando a performance for um problema. O controle de integridade referencial fica por conta do programador.

Uso de Subtipos 293 .

• Casos de subtipos: • A. Subtipos recursivos 294 . Múltiplas referências • B. • Mediante subtipos se pode estabelecer que dois atributos com nomes diferentes correspondem ao mesmo conceito. Especialização de um nível (relação 1-1) • C.Definição de subtipos • GeneXus estabelece as relações através de seus nomes.

Múltiplas referências • Atributos conceitualmente iguais que cumprem regras diferentes (ex. não é possível que na estrutura de uma transação figure o mesmo atributo mais de uma vez. Como fazemos para relacioná-los. as quais cumprem regras diferentes. SOLUÇÃO: chamar as duas cidades de reserva com diferentes nomes de atributos.A. Opção 1) ReservationCityFromId  cidade origem CityId  cidade destino (mesmo nome que a PK de CITY) Opção 2) CityId  cidade origem (mesmo nome que a PK de CITY) ReservationCityToId  cidade destino Opção 3) ReservationCityFromId  cidade origem ReservationCityToId  cidade destino O problema é que ao colocar por exemplo ReservationCityFromId ao invés de CityId. O rol de uma das cidades é o de ser a “cidade de partida” (cidade origem) e o rol da outra é o de “cidade de chegada” (cidade destino).: reservas de passagens). Reservation PROBLEMA Atributos com o mesmo nome { ReservationId* CityId origem CityId destino City { SOLUÇÃO } } CityId * CityName Reservation { City subtipo subtipo { CityId * CityName } Desaparece o problema! } ReservationId* ReservationCityFromId ReservationCityToId Realidade para representar/desenhar: Em cada reserva tem duas cidades envolvidas. é desenhando a transação “Reservation” na forma mencionada inicialmente na transparência. Todavia. GeneXus deixa de inferir que ReservationCityFromId corresponde ao código de uma cidade da tabela de CITY. A forma de representar tanto a “origem” como o “destino” são cidades da tabela CITY. Escolhemos a 3era por maior clareza. sendo que tem nomes de atributos diferentes? ver resposta na próxima folha … 295 . O domínio de ambas cidades é o mesmo. o da tabela CITY. Qualquer das seguintes opções é válida. pois não teria maneira de identifica-los.

se definimos o atributo ReservationCityFromId como subtipo de CityId. então dizemos que CityId é supertipo de ReservationCityFromId. é a mesma que se obteria utilizando diretamente o supertipo. Ao estabelecer que um atributo é subtipo de outro. A tabela estendida obtida com a definição do subtipo. ao mesmo conceito (uma cidade da tabela CITY).Para estes casos GeneXus fornece os SUBTIPOS. Em nosso exemplo. Os atributos que se encontrem numa relação subtipo-supertipo compartilham a mesma definição (tipo de dados). que permitem definir que dois atributos que se chamam diferentes correspondem ao mesmo conceito. Se ReservationCityFromId é subtipo de CityId. estamos especificando que mesmo ReservationCityFromId e CityId são diferentes atributos (de nomes diferentes). 296 . Se realizam os controles de integridade referencial automaticamente. correspondem. estamos estabelecendo uma dependência funcional entre eles.

: mencionar ReservationCityFromName caso queira nesse momento o nome da cidade origem. na mesma tabela (RESERVATION) tem mais de uma referência à outra tabela (CITY) e com valores diferentes. Ex. a forma de indicar ao GeneXus qual os caminhos deve tomar para acessar a tabela destino. Múltiplas referências • Com a definição dos subtipos antes mencionados: • Se estabelecem as seguintes relações: ReservationCityFromId RESERVATION ReservationCityToId CITY • Os controles de Integridade Referencial (IR) são feitos automaticamente entre ambas tabelas quando utilizam suas correspondentes transações. e incluí-los em cada um dos grupos de subtipos. 297 .A. Uma vez definidos os grupos de subtipos que são necessários. é mencionando os nomes de atributos correspondentes. é necessário definir SUBTIPOS. mas como existe dupla referência não se podem utilizar diretamente a partir de RESERVATION (ambigüidade de caminhos e com valores de cidades diferentes). para que os atributos possam ser chamados de forma diferente e realizando todos os controles de integridade referencial. IMPORTANTE: Observe que este caso de múltiplas referências pode acontecer: • na tabela base (*) • como na tabela estendida (*) é o caso do exemplo. Solução definir também subtipos para os atributos secundários de CITY. • Os atributos secundários de CITY: Pertencem a tabela estendida de RESERVATION. RESUMINDO: sempre que a partir de uma tabela se acesse a outra que está em sua tabela estendida por “mais de um caminho” e com “valores diferentes”. o ReservationCityToName caso queira o nome da cidade destino.

deve conter um atributo ou um conjunto de atributos. cujos supertipos. Múltiplas referências Nome de cada grupo de subtipos. e sim que vai inferir em ReservationCityToName o nome correspondente a esse código de cidade. estão relacionados. no nosso exemplo. Por exemplo. ou seja. Os demais atributos do grupo deveram ser do tipo “Inferred”. 298 . não somente é feito de forma automática o controle de integridade referencial (que exista uma cidade com esse código na tabela CITY). IMPORTANTE: Todo grupo de subtipos. GeneXus saberá que o atributo ReservationCityToName será inferido através do atributo ReservationCityToId (e não através do ReservationCityFromId). poderão ser inferidos através da chave. Transação “Reservation” { ReservationId* ReservationCityFromId ReservationCityFromName ReservationCityToId ReservationCityToName } Tabela “Reservation” { ReservationId* ReservationCityFromId ReservationCityToId } Inferido Inferido FK FK Com o grupo estamos indicando que os atributos pertencentes ao mesmo grupo de subtipos. Quando o usuário digita um valor sobre ReservationCityToId. Isto é por ambos pertencerem ao mesmo grupo (ao nome ReservationCityTo). juntos. correspondam a chave primária de uma tabela do modelo. Caso contrário o grupo estará mal definido.A.

país. e de cada uma delas mostrar os dados do cliente (nome. Solução: Devemos diferenciá-los.A.) e do vendedor (nome. Múltiplas referências a tabela estendida • COUNTRY pertence a tabela estendida de SALE por caminhos diferentes e com códigos de país diferentes. mas querendo que continuem representando todas as relações e fazendo automaticamente todos os controles de integridade referencial. Problema: Os atributos de nome CountryId.): • necessitamos um For Each com tabela base SALE e acessar através de sua extensão as tabelas CUSTOMER. país. vendedor e país respectivamente. SELLER e COUNTRY para listar os atributos secundários do cliente. por exemplo listar as vendas (SALE). Um caminho a partir de SALE a COUNTRY: através do País do cliente (CountryId) CUSTOMER SALE SELLER Outro caminho a partir de SALE a COUNTRY: através do País do vendedor (CountryId) Source: Que país imprime? Quais dos caminhos toma? Tem uma ambigüidade no modelo de dados! COUNTRY Layout: Se desejarmos. CountryName e todos da tabela estendida COUNTRY pertencem à tabela estendida SALE por dois caminhos diferentes: 1) através do país do cliente e 2) através do país do vendedor. etc. chamá-los com diferente nome de atributo. 299 . etc.

e fazendo a mudança correspondente na estrutura da transação Sale. Múltiplas referências a tabela estendida Solução Quando queremos o país do cliente da venda: SaleCustomerCountryName st eCu Sal erId om CUSTOMER COUNTRY SALE Sale Sel le rId SELLER Quando queremos o país do vendedor da venda: SaleSellerCustomerName Uma vez definidos os dois grupos de subtipos que se mostram na figura.A. resolve a ambigüidade no modelo de dados! 300 .

301 . temos que lembrar de usar o nome do atributo que corresponda ao que queremos acessar. Por exemplo.A. em todos aqueles objetos GeneXus nos quais gostaríamos de acessar ao código do nome do país do cliente da venda devemos usar atributos SaleCustomerCountryId e SaleCustomerCountryName respectivamente. Múltiplas referências a tabela estendida: Solução SaleCustomerCountryId SaleSellerCountryId Problema resolvido! Uma vez definidos os subtipos.

terá pagamentos. endereço. etc. ao tentar eliminar um registro de “Person”. Cada vez que inserir um registro na tabela TEACHER através de sua transação. são criadas três transações: “Person”. Especialização de atributos Ex. Geralmente é utilizada. são utilizados subtipos. Tanto os estudantes como os docentes compartilham informação em comum (ambos tem um nome. Exemplo “Sistema para uma Universidade”: Neste exemplo. o professor terá cursos atribuídos. quando um objeto do negócio compartilha todas as características de outro objeto. primeiro é verificado que não exista nenhum registro na tabela TEACHER (nem em STUDENT) com o mesmo valor na chave primária. Para representar que tanto os estudantes como os docentes são pessoas. remuneração.B. a checagem da integridade referencial é realizada contra “Person”. o professor e o aluno possuem regras e comportamentos claramente diferenciados. Para representar esta realidade. Definindo que o identificador de “Teacher” é subtipo do identificador de “Person” estamos estabelecendo esta relação. escolaridade. que é própria de cada um. 302 . Por exemplo. “Teacher” e “Student”. Da mesma forma. A diferença pode estar tanto nas propriedades. Estamos em um caso que as regras e o tratamento das entidades da categorização estão claramente diferenciados. como no seu comportamento. etc) mas também possuem informação diferente. mas agrega mais algumas.: Sistema para uma Universidade … PERSON dados comuns a professores e estudantes TEACHER dados próprios dos professores Sistema Teachers STUDENT dados próprios dos estudantes Sistema Students Caso de subtipos “Especialização de atributos”: Quando se está modelando uma categorização. etc. assistência. Na transação “Person” figura a informação em comum. O aluno estará inscrito num curso.

TeacherId é o identificador da transação. será uma chave estrangeira da tabela PERSON. 303 . que serão inferidos da tabela PERSON. • São realizadas as checagens de IR contra a tabela PERSON. Portanto. através da chave estrangeira TeacherId (não estão armazenados na tabela TEACHER). ao ser um subtipo de PersonId. Alem disso.B. A transação “Teacher” tem associada uma tabela que conterá fisicamente somente dois atributos: TeacherId e TeacherSalary. Especialização de atributos “Person” { PersonId* PersonName PersonAddress } } “Teacher” { TeacherId* TeacherName TeacherAddress TeacherSalary “Student” { StudentId* StudentName StudentAddress StudentAverage } • São criadas 3 tabelas físicas. será a chave primária da tabela associada. Os atributos TeacherName e TeacherAddress são subtipos de PersonName e de PersonAddress respectivamente e estão agrupados com TeacherId. serão realizadas as checagens de integridade referencial correspondentes.

que é uma FK na tabela EMPLOYEE. trocamos para ‘Yes’ a coluna Nulls do atributo EmployeeManagerId.um gerente pode ter vários empregados. Por ser EmployeeManagerId subtipo de EmployeeId. então. tem que permitir deixar nulo o atributo EmployeeManagerId. é inferido após ingressar um valor em EmployeeManagerId.cada empregado tem um gerente. são realizadas automaticamente os controles de integridade referencial da tabela com ela própria. a sua vez.isnull(). a relação entre Empregado e Gerente: . tenha um gerente.C. Este controle é realizado com a regra error mostrada na figura. ao inserir os dados tem que realizar os seguintes controles: -quando informar os gerentes. Isto pode ser visto na navegação da transação na página seguinte. -que todo empregado que não é gerente. 304 . O atributo EmployeeManagerName não fica armazenado na tabela EMPLOYEE. Para isto. . Um gerente. Além disso. é um empregado (aqui esta a recursividade). a realidade a ser representada é que “somente os empregados que não são gerentes possuem um gerente”. Subtipos recursivos • Exemplo: Employee-Manager Tabela EMPLOYEE { EmployeeId* EmployeeName EmployeeIsManagerFlag EmployeeManagerId Error(‘Deve ingressar um gerente para o empregado’) if not EmployeeIsManagerFlag and EmployeeManagerId. Este tipo de subtipos se utiliza para modelar as relações recursivas. Por exemplo. } FK É possível ter uma tabela subordinada a si mesma utilizando subtipos.

C. Subtipos recursivos • Listagem de navegação detalhada: 305 .

306 . • Pelo menos um dos supertipos do grupo (ou conjunto de supertipos do grupo) deve(m) corresponder a PK de uma tabela do modelo.Considerações • Quando se define um subtipo este "herda" a definição do supertipo.

PATTERNS 307 .

trabalhar com os países de uma forma mais vistosa e amigável que a que brinda somente a transação..Patterns: Cenário Filtro sobre os dados Paginação Tendo a transação Country e a transação Customer. . de tal forma que mostre um número fixo de registros por página. queremos ter a aplicação mais vistosa.. Visualizar num grid os países existentes. com consultas com vistas mais completas e com algum aumento de produtividade. com a possibilidade de filtrar por nome de país. Por exemplo. e fixando a paginação ao grid.

. ou selecionar um dos mostrados no grid.... para poder modificá-lo ou eliminá-lo.assim como poder ingressar um novo país (mediante a transação Country). .Patterns: Cenário New Country Update Country Delete Country T r a n s a c t i o n .

. incluindo os clientes associados..Patterns: Cenário .. ..ou incluso ver a informação completa desse país.

Padrões disponíveis: • Work With • Category Seletores dentro das Transações Uma vez aplicado o padrão. se obtenha todo o desenvolvimento correspondente ao “Work With Customers” e “Work With Countries” para ambiente web (telas vistosas que implementam as consultas. considerando seus dados específicos. ter que resolver partes muito similares mas não exatamente iguais. Por exemplo. com ordens. filtros. e gerar todos os objetos GeneXus necessários para implementar certa funcionalidade. Surgem então os Patterns. chamadas às transações correspondentes. e mais). É natural ao desenvolver. apesar de ditos objetos serem bem diferentes. os “Work With Customers” e “Work With Countries” respectivamente. se em uma Base de Conhecimento tem modelados os objetos da realidade Customer e Country. opções de ordens da consulta. um conjunto de variáveis para utilizar em filtros. . oferecendo a possibilidade de aplicar um padrão (pattern) às instâncias desejadas de uma Base de Conhecimento. é possível aplicar o padrão “Work With” na Base de Conhecimento. possuem muitas coisas em comum: um grid no form. Seguindo com o exemplo mencionado inicialmente. chamadas à transação correspondente para atualizar a base de dados. todos os objetos gerados ficam como parte da Base de Conhecimento. etc. de tal forma que partindo das transações “Customer” e “Country” (e caso se deseja outras)..Patterns Generalidades Definição Padrões que podem ser aplicados a uma KB para implementar automaticamente certa funcionalidade.

: . Tela View: Registro selecionado. Etc. múltiplas ordens. com a informação associada. delete. chamada a transação.Patterns Work With Gera a partir de uma Transação Tela Work With: consulta interativa. filtros. update. display) • Possibilidade de incluir chamadas próprias a objetos • Link em cada linha do grid a tela ‘View’ A tela View mostra: • A informação do registro selecionado no grid Work With • Um tab control com: • Um tab com a informação do registro • Um tab para cada tabela subordinada a tabela base do registro no grid Work With. Work With Transação View A tela Work With oferece: • Consulta interativa • Múltiplas ordens • Filtros • Chamada à Transação nos diferentes modos (insert.

basta editar a instância (selector “Work With” da transação). Display) e o país. . marcar o check box e gravar. Update. Pronto! Com isso são criados automaticamente os objetos GeneXus que implementam o pattern (em particular a tela de seleção e filtro e a tela de View que mostramos antes). Delete.Patterns Aplicação Abrir a Transação Selecionar o padrão a ser aplicado (aparecerá a instância por default) Marcar a opção “Apply this pattern on save” Salvar a Transação Para aplicar o pattern sem demoras. Assim mesmo se modificará a transação para que agora receba por parâmetro o modo (Insert.

No entraremos em detalhes neste momento. 314 . aparece o nome do pattern aplicado a mesma (em nosso exemplo WorkWithCountry) e todos os objetos que GeneXus deve criar para implementar. abaixo o nome da transação. e 2 objetos de tipo Web Panel. abaixo da própria transação: Uma vez gravada a instância. no folder view. A diferença é que um Web Component pode ser incluído dentro de outro objeto. Onde? No Folder View.Patterns Work With: objetos gerados Consequencia: São gerados na KB os objetos que já vimos em execução. São muitos similares. Em nosso caso serão criados 2 objetos de tipo Web Component.

basta editar suas propriedades a partir do nó Attributes e colocar a propriedade Visible=False. por ser CountryName o atributo descriptor. Caso não se queira visualizar o atributo CountryId no grid da tela Work With. . O primeiro tab terá a informação do país selecionado. Não pode ser eliminada porque é a chave primária da transação Country. será criado: • Tela Work With: • Terá um grid com os atributos CountryId e CountryName • Poderá ordenar e filtrar por CountryName. 1 N Ao aplicar o pattern Work With na Transação Country. e o segundo terá a informação dos clientes pertencentes a dito país (porque existe uma relação 1-N entre as transações Country e Customer). • Poderá chamar a transação nos diferentes modos • Tela View: Mostrará dois tabs.Patterns Exemplo Aplicação do pattern Work With à transação Country.

ou mostra todos os países. Onde se configura este valor por default? Veremos numas páginas mais adiante. São muitas as propriedades oferecidas nas instancias correspondentes ao padrão Work With. para personalizar o comportamento dos objetos que serão gerados. Na continuação descrevemos algumas delas. Upd. Display Condition. As possibilidades e seus valores por default são: Insert: True Update: True Delete: True Display: False Na instância aparece <default> ao lado de cada uma das propriedades anteriores. Seus subnós são: Modes (Ins. O nó Selection oferece as propriedades relacionadas a tela Work With que se gera para a instância. Del. Para cada modo poderá especificar-se uma condição. Delete Condition. Update Condition.Patterns Começando a associar… janela Work With Se coloca no país indicado. São fornecidas as seguintes propriedades para esse propósito: Insert Condition. a chamada para esse modo somente será habilitada a avaliação da condição é verdadeira (Exemplo: CountryId=10). Dis) Este nó permite definir em quais modos se pode chamar a transação. . Se define uma condição associada a um modo.

Patterns
Modificando a instância do Pattern Work With
Agregar, eliminar, ocultar Atributos. Especificar os modos de chamada à transação Definir ordens e filtros. Agregar, eliminar, modificar Ações. Agregar, eliminar, modificar Tabs.

Posicionar-se no nó correspondente e pressionar o botão direito do mouse.

Attributes Este nó permite definir quais atributos desejam mostrar no grid (e para cada atributo, várias propriedades podem ser personalizadas). Orders É possível oferecer ao usuário final várias ordens possíveis para ver o resultado da consulta (isto é, as linhas mostrando os dados no grid). Utilizando o botão direito do mouse pode ser definida uma nova ordem (seu nome e composição). Cada ordem pode estar composta por vários atributos (podendo indicar para cada um deles se deseja ordem ascendente ou descendente). Um combobox será apresentado na tela WorkWith oferecendo todas as possíveis ordens a serem selecionadas, para que o usuário final escolha e os dados sejam apresentados no grid ordenados pelo mesmo. Filter Este nó permite definir condições de filtro, para que no grid sejam mostrados somente os registros que cumpram com as mesmas. Actions O nó Actions permite incorporar ações próprias na tela WorkWith. Isto é, permite agregar botões (dentro ou fora do grid) que chamem aos objetos indicados, com seus parâmetros correspondentes. O nó Actions não está visible por default, estando posicionado no nó Selection e pressionando o botão direito do mouse, a opção Add Actions é oferecida para ser agregada. Uma vez agregado este nó, estando posicionado sobre o mesmo e pressionando o botão direito do mouse, se oferecerá a opção Add Action que permitirá agregar uma ação com seu nome de ação, caption, objeto chamado, etc. O nó View por sua vez, oferece as propriedades relacionadas a tela View gerada para a instância. Mostra toda a informação de um registro, que foi selecionado no grid do WorkWith (a informação do registro é mostrada em uma aba de um tab control, e além disso tem uma aba com um grid para cada tabela diretamente subordinada, para mostrar a informação relacionada).

Patterns
Personalização- Exemplos
1) Ocultar atributo CountryId do grid.

F4

Por que ocultar ao invés de eliminar?

O atributo CountryId, diferente do CountryName, não pode ser eliminado do grid, isso porque é um atributo que se envia a transação ‘Country’ quando o usuário deseja modificar ou eliminar o país mostrado numa linha do grid do Work With.

318

Patterns
Personalização- Exemplos
2) Eliminar modo Delete a partir do grid.

F4

Ao editar as propriedades estando posicionados no nó da instância que se mostra, podemos observar que cada um dos modos que se pode chamar uma transação (para inserir, modificar, eliminar ou incluso mostrar) estão listados como propriedades. Podemos ver também que aparece uma propriedade Export que permite exportar os dados a uma planilha excel. Outra vez aqui podemos apreciar que cada uma das propriedades possui o valor <default> que ainda não sabemos de onde é pego. Mas se queremos fixar um valor independente de qual seja o default, podemos editar o combo box que apresentará três valores: <default>, ‘true’, ou ‘false’. Fixamos o valor da propriedade Delete em ‘false’. Podemos ver em execução a repercussão. Não aprece no grid a primeira coluna que contêm a imagem que permitia eliminar o país. Agora não se pode eliminar países a partir dessa tela. Observe também como desapareceu do grid o atributo CountryId. Ocultamos ele na página anterior.

319

Patterns
Personalização- Exemplos
3) Agregar uma ação de chamada a um objeto na tela View Country.
a) Click com o botão direito sobre o nó selection, escolha add/actions b) Click com o botão direito sobre a ação criada e escolha add/action.

Patterns
Personalização - Exemplos
c) Definir a Ação editando suas propriedades (F4).
Nome da ação e objeto que se chama.

Botão fora do grid.

d) Finalmente em execução, se observa o botão foi do grid.

Já havíamos definido o objeto BillingProcess para realizar o faturamento do mês de todos os clientes. Aqui estamos agregando um botão fora do grid, que ao pressioná-lo chama outro objeto GeneXus que havíamos criado anteriormente.

321

Patterns
Associando... tela View

O nó View por sua parte, oferece as propriedades relacionadas a tela view que se gera para a instância. Mostra toda a informação de um registro, que foi selecionado no grid do Work With (a informação do registro é mostrada em uma aba de um tab control, e além disso tem uma aba com um grid para cada tabela diretamente subordinada, para mostrar a informação relacionada).

322

Patterns
Personalização - Exemplos
1) Tirar atributos CustomerGender Customer da tela View Country. e CustomerStatus do tab

a) Posicionar-se sobre o atributo e eliminá-lo com a tecla de eliminação do teclado ou botão direito/Delete.

Neste caso se não queremos que os atributos CustomerGender e CustomerStatus sejam vistas no grid em execução, não necessitamos ocultá-los. Podemos diretamente eliminá-los.

323

Patterns
Personalização - Exemplos
2) Agregar um filtro por CustomerName no tab Customer.

a) Click com o botão direito sobre o tab Customer

b) Indicar o atributo sobre o cual filtrar, editando as propiedades (F4).

Uma vez executado o passo a) e escolher ‘Filter’ aparecerá um novo nó Filter imediatamente depois do nó Attributes, com 2 subnós: Attributes e Conditions. Depois, no passo b), deverá posicionar-se no subnó Attributes e fazer botão direito, onde se oferece a possibilidade de agregar um atributo de filtro. Ao editar as propriedades, você deverá pressionar o combro box vai mostrar uma janela onde se ingressa o atributo (em nosso caso, CustomerName). Com isto se cria automaticamente uma variável com o mesmo nome que o atributo &CustomerName, que será o control que aparecerá em execução para que o usuário digite ali o filtro. Vejamos o passo seguinte...

324

325 .Exemplos (Continuação) c) Definir a condição correspondente.Patterns Personalização .

cada instância contêm a propriedade UpdateTransaction. permitem definir o comportamento depois que se insere. o comportamento será o mesmo que se houvesse selecionado o valor Create Default. Enquanto as propriedades AfterInsert. Only rules and events: Somente as regras e eventos serão modificados. que oferece os seguintes valores: Do not update: A transação não será modificada (web form. regras e eventos serão mantidos). assim como os eventos e regras.Patterns Valores por default para as propriedades Propriedades (F4) O padrão WorkWith além de gerar objetos novos. modifica ou elimina um registro. Create default: Regras. No que diz respeito ao form. Relacionado a isto. AfterUpdate e AfterDelete.. etc. A partir da segunda vez que o padrão é aplicado. também modifica as transações. para que sejam chamadas pelos objetos gerados pelo pattern. Os valores possíveis para cada uma delas são: • Default • Return to caller • Go to View • Go to Selection . O valor por default para esta propriedade é Apply WW Style. e se modificará o style área. eventos e form da transação (tanto data área como style área) serão modificados. não se modificará a data área do form da transação (caso tenha sido personalizada com GeneXus e deseja manter). agregando a regra parm. será como selecionar a opção Create default a partir do GeneXus. Apply WW Style: A primeira vez que o padrão é aplicado. o web form não é modificado.

Isto é. que nas imagens anterior era de 3 (se mostravam em 3 linhas por página do grid) se configura no nó Grid. Nós tínhamos alterado para 3 para que não fosse mostrado as imagens complestas.Patterns Pattern Settings Configuração das propriedades gerais (para todas as instâncias) Preferences \ Patterns Aqui estão centralizados os <default> para toda instancia. Podemos ver que o nó Template oferece algumas propriedades que mencionamos na página anterior. O tamanho da página dos grids do work with. O valor que tem Page é 10. o valor do domínio enumerado Pages criado por GeneXus automaticamente ao aplicar o pattern na primeira vez.Rows. . O valor por default desta propriedade é Page.

não vai ser atualizado automaticamente o grid WW com esse atributo (ou seja. se deve selecionar a partir do Menu Edit / Apply Default (a parte onde se tem aberto o objeto) ou Apply Default (All parts). se modificar o web form de um WW (não fica como default). voltando o default de todas as partes que haviam sido modificadas. A implementação baseada em Defaults permite ter dinamismo entre a Transação e o padrão Não é necessário reaplicar o padrão. Cada parte de um objeto é gerada como Default. A implementação baseada em Defaults permite ter dinamismo entre a Transação e o padrão • Alterar propriedades na definição do padrão (Pattern setting) • Alterações na instância (agregar um novo filtro) • Alterações na Transação (agregar um novo atributo) Se quiser voltar o dinamismo. as alterações são vistas ao abrir o objeto novamente O dinamismo é mantido para todas as partes default do objeto • Opção Edit / Apply Default do Menu para voltar o default de uma parte ou de todas as partes (All parts) O dinamismo mencionado se mantêm para todas as partes default dos objetos. Todos os objetos gerados por Patterns estão baseados no esquema de Defaults de GeneXus. Cada parte (Form. Regras.Patterns Dinamismo entre a Transação e Patterns Todos os objetos gerados pelos Patterns estão baseados no esquema de Defaults de GeneXus. . e se agrega um novo atributo na TRN. Eventos) de cada objeto é gerado como Default. Caso alguma parte do objeto tenha sido modificada. Por exemplo. deverá ter novamente as partes como default. Para isto. esta deixa de ser Default. não será agregado dito atributo).

Aparecerá a mensagem: Ao confirmar a mensagem • Se eliminarão todos os objetos gerados por Patterns associados na Transação. pressionar botão direito / opção “Delete” ou pressionar a tecla DEL.Patterns Como eliminar os objetos gerados por Patterns Selecionar a instância. • Se eliminarão todos as regras e eventos agregados por Patterns na Transação. . • Será desmarcada a opção “Apply this pattern on save” da Transação.

Objeto Web Panel 330 .

Documentação: Permite a inclusão de texto técnico como documentação para os desenvolvedores. que se ativa em resposta a certas ações provocadas pelo usuário ou pelo sistema. definir quais variáveis não queremos que sejam aceitas no form mas utilizadas para mostrar informação. Elementos que as compõem: Os elementos das web panels são: Web Form: Cada web panel contem um form Web. Condições: É para definir as condições que devem cumprir os dados a ser recuperados (filtros). Ajuda: Permite a inclusão de texto de ajuda. Subrotinas: São rotinas locais na web panel. que os usuários podem consultar em tempo de execução da web panel. para que o usuário possa interagir com o mesmo. São flexíveis.Web Panels Generalidades Definição Objetos GeneXus que permitem ao usuário realizar consultas interativas na base de dados através de uma tela em tempo de execução. declarar quais parâmetros recebe. o qual deve ser desenhado pelo analista agregando variáveis. etc. atributos. Eventos: As web panels empregam a programação orientada a eventos. Propriedades: São características a serem configuradas para definir certos detalhes referentes ao comportamento geral da web panel. . para múltiplos usos. assim como outros controles. Regras: As regras de uma web panel permitem definir certos comportamentos pontuais de dito objeto. Este tipo de programação permite definir código ocioso. Por exemplo. Nesta seção de uma web panel é onde se define o código ocioso associado aos eventos que podem ocorrer durante a execução da web panel.

No evento Enter da web panel (associado ao botão Billing Generation). . e ao selecionar o botão Billing Generation. De modo que a definição desta web panel é para que o usuário ingresse a faixa de datas. a web panel contem duas variáveis &StartDate e &EndDate como se mostra acima. se obtêm e gravam as faturas cujas datas se encontrem na faixa especificada. se execute o processamento das faturas. o usuário pode ingressar valores nas variáveis &StartDate e &EndDate visto que nas web panels as variáveis por default são de entrada. Em tempo de execução.Web Panels Para o ingresso de dados 1 Event Enter No exemplo.

se acessa o registro relacionado da tabela estendida necessária. 1 Ao contrário do que acontece com os atributos nas transações (exceto os inferidos ou os que tem regra noaccept ou propriedade Enabled desabilitada). quando GeneXus encontra atributos no form. a web panel estará bem programada se além disso se agregar um filtro que determine “esse” registro a ser mostrado.Web Panels Para exibir dados de um registro Customer { CustomerId* 2 CustomerName CountryId CountryName CustomerAddress CustomerGender CustomerStatus CustomerPhoto } blob Tabela base: CUSTOMER parm(in: CustomerId ). temos a regra parm que ao receber no atributo PK da tabela somente vai recuperar um registro. qual intenção do programador ao ter colocado isso? Pois. passando por parâmetro o código do cliente do qual se quer mostrar a informação. um grupo de grupo de Data Providers. os atributos que figurem serão de consulta1. isto é.. Em nosso caso.. como é o caso do exemplo. • Web panel com uno ou mais grids: veremos em seguida. etc. Pois acontece o mesmo que com um for each. Então. o que está pedindo implicitamente é que se busque os dados correspondentes a base de dados para mostrá-los. GeneXus determina uma tabela base da web panel. é porque o analista necessita acessar a informação de um registro de uma tabela (e eventualmente dos registros relacionados pela tabela estendida).. No caso geral: cada grid mostra muitos registros de uma tabela (e sua informação associada). assim como faz para um for each. Então GeneXus deve acessar a base de dados para recuperar seus valores. Precisa ser chamada a partir de outro objeto. para obter o valor do atributo requerido (em nosso caso acessa a tabela COUNTRY para recuperar o valor de CountryName). como no caso que estamos mostrando. Neste caso. mas já podermos pensar. mostrará a informação do registro encontrado.. desde o registro da tabela base. De quais tabelas? Vai depender se a Web panel possui grids ou não: • Web panel plana (sem grid): os atributos estão “soltos” no form. Que informação? A que reside nos atributos que figuram no form. Mas o atributo CountryName não se encontra na tabela CUSTOMER. As inferências que GeneXus realiza são as seguintes: Ao se tratar de uma web panel. Como? Buscando a mínima tabela estendida que contenha os atributos. CustomerId. Qual o sentido de colocar um grid? Mostrar informação repetitiva. Se isso acontece. GeneXus vai a tabela CUSTOMER e filtra pelo atributo recebido por parâmetro. Com a web panel anterior. . São mostrados os dados do cliente A web panel mostrada acima foi criada para exibir os dados de um cliente. Uma web panel é um objeto tipicamente utilizado para mostrar informação.

ou por ambos. Simplesmente dizendo quais atributos deseja mostrar. clientes). então. Nesta web panel não tem regra parm que estabeleça filtro algum. GeneXus determina a tabela base desta web panel (sendo que a tabela estendida seja a mínima que cumpre que contenha todos os atributos referidos). é como o print que se executa em cada iteração do for each da listagem. não tem que especificá-lo. a tabela da base de dados navegada em busca da informação requerida. ficando somente registro de CUSTOMER. Se ao invés de mostra esta informação em tela. e portanto. também permite filtrar os clientes que se quer ver em cada oportunidade. Observe que este exemplo somente difere do anterior. tem atributos.Web Panels Para exibir múltiplos registros: Grids Exemplo: Mostrar todas as Faturas 3 CUSTOMER COUNTRY Tabela base: CUSTOMER O que diferencia está web panel da anterior é que ela não é plana. se está indicando que vai mostrar uma quantidade indefinida de dados (neste caso. sem necessidade de mais informação. seja por nome do cliente. isto é. Das tabelas CUSTOMER e COUNTRY e da relação entre ambas é Na1. Também conseguiremos mais adiante que esta web panel além de mostrar os clientes da base de dados no grid. que os atributos aparecem num grid. . Por isso as variáveis aparecem no form. necessariamente terá tabela base. quisermos uma listagem. Quando se incluiu um grid num form. vamos criar um procedimento com um print block ‘customer’ com os atributos CustomerName e CountryName e no source programaríamos: for each print customer endfor INVOICE CUSTOMER Isto é a análogo. somente que o for each está implícito. Visto que nesta web panel tem envolvidos atributos. Cada linha do grid que se carrega. Existe um grid. não precisa filtrar. GeneXus infere que deseja acessar a base de dados.

e nesse caso não terá necessidade dessa informação. como veremos na página seguinte.. Depois veremos casos em que isso não acontece (grids sem tabela base). . É por isso que falamos que nesse caso tem um for each ‘implícito’. For each implícito: para c/customer buscar nome de país associado e Load se carrega linha no grid.Web Panels . . Observe o exemplo.. se carregam uma a um os quatro... Se agora queremos que o usuário possa filtrar os clientes que deseja ver.. .entra em questão as variáveis que definimos na parte fixa do form..... Load automático Customer tabela CustomerId 1 2 3 4 . 3 load l oad l oad l oad Country table CountryId 1 2 3 4 . CountryId 2 2 1 4 . .. CustomerName Susan Jones Richard Smith Martina Rodríguez Hugo Romero .. CountryName Uruguay United States Italy Venezuela . 335 ... . Base de dados Quando GeneXus pode determinar automaticamente uma tabela a percorrer para carregar as linhas do grid.. que se na tabela existem 4 registros. o faz. .

Nota: Assim mesmo. mediante o selector Conditions. Em nosso caso.Web Panels . não somente podem estabelecer condições locais ao grid (for each). critério de ordenação da tabela percorrida. É por essa razão que foi agregado as variáveis &CustomerName e &CountryName no form da web panel. da mesma forma que num procedimento. pode determinar. igual se fazia com um for each. para não ter que repetir cada vez a mesma condição. aparece un de nome ‘Conditions’.”) equivalem as que apareciam nas cláusulas where de um for each (ou grupo repetitivo de data provider).filtrando Exemplo: Mostrar os clientes que cumprem condições: 3 Por default de entrada Observe como na janela de propriedade do control Grid. Observe que as condições (separadas com “. como se mostra acima no exemplo. por questões de otimização.. para que o usuário possa ingressar ali valores que operem como filtros sobre os dados a mostrar.. Depois veremos que se estiverem em grids são por default de saída. estabelecemos filtros com o operador like. mas também gerais. Da mesma maneira. Isto tem sentido quando tiver mais de um grid (for each). Clicando no combo abre um editor para especificar as condições booleanas que devem cumprir os registros para ser carregados como linhas do grid. As variáveis na parte plana do form de web panels são por default de entrada. 336 .

Client Web Panels . e do control web utilizado para filtrar... Load Load . DateTime e Numeric. Para Check boxes e Radio buttons. estes eventos pode associar código para que se execute nesses momentos específicos. • No Dependendo do tipo de dados do filtro. No caso de filtros em controles edit.. as condições são avaliadas ao sair do campo. para tipo de dados Character. Conclusão: Existem dois eventos do sistema que ocorrem no momento da carga do form (Refresh) e da carga de cada linha do grid (Load).. são aplicados quando o usuário vai digitando. as condições são avaliadas quando se abandona o campo. se dispara o evento Load carregando o grid segundo os novos valores das variáveis.. a condição será aplicada quando se está digitando ou ao abandonar o campo.com refresh automático Re fre sh 3 Server Eventos do sistema: Refresh e Load.. Como veremos.. Execução: o que acontece no cliente e no servidor ao ter a propriedade por default e um grid com tabela base? 1ª execução (variáveis vazias): For each CUSTOMER guardar em memória CustomerName acessar o registro de COUNTRY relacionado guardar em memória CountryName carregar (load) linha no grid com ambos valores N-ésima execução (altera o valor da variável das conditions): Automaticamente no browser do cliente se detecta a mudança refresh no servidor para voltar a carregar o grid com os registros que cumpram as condições (com os novos valores das variáveis) load para cada linha. DB A propriedade Automatic Refresh que se encontra a nível da Web Panel pode ter os seguintes valores: • When variables in conditions change (valor por default): depois de chamar automaticamente o refresh. No caso de filtros combo boxes ou dynamic combos. as condições são avaliadas quando o valor é alterado. Para tipo de dados Date.. 337 .

habilitar check box. Observe que se o tipo de dados da variável &select booleano. Para assegurar que o usuário somente tente ‘ativar’ clientes ‘On Hold’.. programando o evento Load 3 Agregamos ao grid atributo CustomerStatus e a variável &select booleana. Além disso um botão para efetivamente ativar todos os clientes marcados. Somente habilitar check box para os ‘On Hold’: Quando se carrega cada linha do grid. brindando a possibilidade de os passar para o estado ‘Active’. se o valor do atributo CustomerStatus da tabela CUSTOMER a ser carregado é On Hold.. e uma variável booleana &Select.. para poder ativá-los marcando check box e pressionando botão ‘Activate’. Mas isto o faremos num segundo momento. 338 . agregaremos ao grid o atributo CustomerStatus que mostra o estado. desejamos que somente apareça habilitado este check box quando corresponde. Ampliaremos a funcionalidade de nossa web panel. por default aparece no grid como um check box. Para fazer isto... o evento Load. isto é... e para aqueles que estiverem ‘On Hold’. Antes queremos: 1.. Intenção: para aqueles clientes com estado ‘On Hold’. permitindo ver o estado de cada cliente. que permitirá ao usuário selecionar aqueles clientes que deseja ‘ativar’.. para ele necessitaremos programar a carga de cada linha..Web Panels .

. Se dispara uma vez para cada registro da tabela base a ser carregado.. 339 .. ..OnHold &select... estamos em condições de implementar a ‘activate’. programamos o evento Load do grid que vemos acima..Enabled = 0 endif endevent Isto é. O evento Load é disparado para cada linha que vai carregar no grid... No exemplo. CustomerStatus A O C A .. (tendo código programado ou não) Na seção Events da web panel..Enabled = 1 else &select.. Ao se tratar de uma web panel com um único grid. Agora sim. encontrando este comando ou não. E esse é o código que incluímos no evento. que poderá ser o evento Enter ou um de usuário.. antecipando a possibilidade futura de agregar outro grid no form da web panel.. customerGrid é o nome que demos ao control grid no form.. também poderíamos ter programado o evento Load: Event Load if CustomerStatus = Status. programando o evento Load 3 Customer tabela CustomerId 1 2 3 4 .. .Web Panels .. . não é necessário qualificar o evento com o nome do grid. no caso de uma web panel com um único grid.. para efetuar uma ação.... para isso precisamos associar ao botão um evento. . CustomerName Susan Jones Richard Smith Martina Rodríguez Hugo Romero . O que fazemos no exemplo é aproveitar este momento imediatamente anterior a carga. Igualmente recomendamos fazer...

e editar suas propriedades. devemos alterar o estado do cliente correspondetne.. el hecho de representar una estructura repetitiva. quando o usuário pressiona o botão ‘Confirm’. • Variables en un grid pasan de ser Read only (de salida) por defecto. etc.. se o usuário marcou a variável boleana &Select f (check box). sobre alguna columna del grid). 340 .. Obsérvese que el comando For each line sólo tiene en común con el comando For each estudiado antes.Active &customer. En nuestro ejemplo hemos definido una variable &customer. para recorrer las líneas ya cargadas en un grid. Ativar os clientes ‘On Hold’ selecionados: 3 Comando For each line. como cuando presiona la tecla Enter. El Enter será un evento del sistema. mediante la cuál cambiaremos a estado ‘Active’ todas las líneas del grid marcadas por el usuario. Ao inserir o botão no form da web panel.Load( CustomerId ) &customer. por default se pode observar que o botao esta associado ao evento Enter (ver propiedad OnClickEvent). En este ejemplo veremos a la vez: • Posibilidad de definir eventos de usuario y asociárselos a controles o de utilizar el evento Enter del sistema. Click. el for each line recorre las líneas de un grid. • Comando For each line. cuando se utiliza comando for each line en ese grid (también cuando se programan eventos OnClickEvent. a ser de entrada..Save() Commit endif endfor &customer BC ‘Customer’ No exemplo. necessitamos percorrer todas as linhas do grid. Percorre linhas de um grid For each line in customerGrid if &select &customer. Para ello recorremos el grid con el comando for each line. de ‘On Hold’ a ‘Active’. e para cada uma delas. La diferencia más importante: mientras el for each recorre registros de una tabla (base) de la base de datos.CustomerStatus = Status. evento Enter 2..Web Panels . que se ejecuta tanto cuando el usuario hace clic sobre el control asociado. Business Component Customer.

Active &customer. ao invés de utilizar o evento do sistema Enter.Load( CustomerId ) &customer. 341 .Save() Commit endif endfor Outra possibilidade. Isso é realizado seguindo os passos que estão acima.CustomerStatus = Status. o evento de usuário 2. Ativar os clientes ‘On Hold’ selecionados: 3 For each line in customerGrid if &select &customer. Como podemos ver.. a maioria dos controles presentes em um form tem a propriedade OnClickEvent associada. Poderá ser um evento do sistema (Refresh. é definir um evento de usuário.Web Panels . Essa propriedade permite especificar um evento a ser disparado quando o usuário faz clique sobre o controle. Enter) ou um evento definido pelo usuário..

todas as variáveis que estão dentro do grid passam a ser de entrada. etc): modifica o valor por default e todas as variáveis do grid passam a ser de entrada. etc..Web Panels . porque é unicamente de leitura e por consequencia não pode ser alterado. Para ter algumas de saída: Propriedade: Read Only 3 A parte fixa da web panel por default é de entrada. 342 . acontecerá o mesmo. É possível indicar neste caso quais são as variáveis que não podem ser modificadas através da propriedade ReadOnly. como já vimos anteriormente para as variáveis utilizadas para filtrar os clientes (customers) mostrados no grid. associado (ou evento de usuário especificado na propriedade OnClickEvent). Se dentro de um evento da web panel ter o comando For each line. Variáveis de grid • Por default todas as variáveis de um grid são Read-Only • For each line [in grid] ou qualquer evento sobre as linhas ou colunas (OnClickEvent. DblClick. 2. Se dentro da fila tem algum controle com um evento click... Como aceitar dados em um grid É possível aceitar dados nas variáveis de um grid dependendo da programação dos eventos existentes no objeto: 1. IsValid. Click. dblClick. Como mostrar dados no grid Por default todo atributo e variável que está dentro de um grid se mostra em execução como texto.

Para que o usuário possa selecionar uma linha do grid. de onde é extraído? Da base de dados? Não. ao invés de não agregar o atributo? Faça a seguinte reflexão: o atributo CustomerId enviado por parâmetro ao executar o evento ‘Select customer’. é suficiente ‘prender’ a propriedade ‘AllowSelection’ do grid. Quando o usuário seleciona no grid a segunda linha.Call( CustomerId ) endevent Continuamos ampliando nosso exemplo. É por esta razão que se não colocarmos nenhuma coluna correspondente a CustomerId no grid. Mais especificamente. é o que está carregado no grid. agora queremos que o usuário possa selecionar uma linha do grid (um cliente) e pressionando botão ‘Select customer’ para chamar a web panel que havíamos implementado anteriormente. Por que colocar a coluna correspondente a CustomerId e ocultá-la. • Permitir que o usuário selecione uma linha do grid para fazer algo com ela..Web Panels . visíveis e ocultas. para cada grid existirá um arquivo temporário que contem a quantidade de colunas que o grid possuir.. correspondente a essa linha (e nunca na base de dados!). está posicionado nesse arquivo temporário. e pressiona o botão ‘Select customer’.ocultar atributos do grid e permitir seleção de uma linha 3 Event ‘Select customer’ CustomerView. não estaríamos passando valor algum a CustomerView. Neste exemplo vemos duas funcionalidades: • A necessidade de colocar uma coluna no grid oculta (não visível). 343 .

Eventos: atributos soltos (fora de for eachs) Como GeneXus determina uma tabela base para percorrer automaticamente para carregar o grid da web panel? Se existir algum atributo em pelo menos um dos 3 lugares mencionados.Load( CustomerId ) &customer.Enabled = 0 endif endevent + 3. Grid: • atributos das colunas (visíveis+invisíveis) (fora do grid) 3 • propriedade Order • propriedade Conditions • propriedade Data Selector Event ‘Activate’ For each line in customerGrid if &select &customer. quando tratemos o caso de múltiplos grids em uma web panel.Load if CustomerStatus = Status. A tabela base dessa estendida. Conditions ou using Data Selector.Enabled = 1 else &select. e nos eventos programa programados no selector de Eventos. isto não vai ter sentido. Observe que somente programamos o evento Load para tomar a decisão para cada línea que vai ser carregada no grid. Veremos a forma de determinação das tabelas bases nesse caso. somente os atributos que estejam ‘soltos’ dentro do evento.Active &customer. será a percorrida automaticamente e carregada com o Load.Call( CustomerId ) endevent Event customerGrid. Importante: A forma de determinação da tabela base de um grid dependerá se existir outro grid na web panel ou se é o único. que habilitará ou não para a mesma variável &select que permitirá ao usuário marcar o check box.Web Panels Determinação tabela base 1. fora de um comando for each de acesso a base de dados).CustomerStatus = Status. e determina a mínima tabela estendida que os contenha. Atributos soltos no form + 2. ele extrai os atributos encontrados ali (parte fixa do Form. 344 . Quando existir mais de um grid na web panel. Para determinar a tabela base. e cada grid passará a ter cada grid passará a ter ou não tabela base. isto é. no Grid. tanto nas colunas como nas propriedades Order. Neste caso se diz que a própria Web panel tem tabela base.Save() Commit endif endfor endevent Event ‘Select customer’ CustomerView. O resumo apresentado aqui corresponde a um único grid.OnHold &select. GeneXus poderá encontrar a tabela base. É a do grid.

Estamos falando de um controle de corte. 4 Mostrar o total de faturas por dia (podendo ter um filtro entre as datas informadas) Cada línha do grid não corresponde a cada registro da tabela INVOICE. e para cada grupo.. é quando deseja que seja carregado para cada registro de uma tabela.. como produtos de cálculos. é mais natural implementar o grid sem tabela base. &InvoiceDate = InvoiceDate &Amount = 0 for each defined by InvoiceDate &Amount += InvoiceAmount endfor print InvoiceInfo endfor Estamos apresentando aqui outro exemplo. No caso que se quer carregar uma linha do grid como produto a ser lido de vários registros da base de dados (N registros – 1 linha). O caso do exemplo: não queremos carregar para cada fatura uma linha. For each order InvoiceDate where . Vejamos como implementar com uma web panel. uma linha do grid (1 registro – 1 linha).. mas sim queremos agrupar as faturas por data. 345 . Se tivéssemos que implementar uma listagem PDF ao invés de uma web panel.. etc... o que faz é agrupar todas as faturas de uma data e totalizar … se fosse um pdf. para que possamos observar um caso que surge a necessidade natural de implementar um grid sem tabela base. saberíamos como programar (como o fazemos acima) . carregar uma linha que some seus valores..Web Panels Para exibir múltiplos registros: Grid (sem tabela base). seria implementado. O caso de implementação natural de um grid com tabela base.

É necessário quando o grid não tem tabela base.. neste GeneXus realiza menos inferências.Web Panels anteriores) não tem tabela base 4 Para exibir múltiplos registros: Grid (sem tabela base). Não tem atributos (em nenhum dos 3 pontos GeneXus não pode inferir carga automática: tem que programar evento Load ocorre somente 1vez Ordem de carga de uma linha no grid (as variáveis assumem valores nesse momento) O objetivo do comando LOAD é agregar um linha num grid.. e se deseja agredar uma linha ao grid. de acordo com a lógica correspondente. Portanto neste caso é imprescindível que seja programado. 346 . O evento Load vai ocorrer uma vez. Uma vez que for atribuído a cada variável seu valor. Frente ao caso do grid com tabela base. visto que nesse caso não será agregado nenhuma linha de forma automática. e o grid retornará vazio caso não seja programado. o comando LOAD deverá ser programado. Observe que neste caso a implementação fica por conta do analista. O comando LOAD somente pode ser especificado dentro do evento Load do grid de uma web panel.

sem código. Para isso deverá. Aqui não tem o refresh automático.. 347 . agregar um botão associado ao evento Enter. quando o usuário modifica os valores das variáveis que interveem nos filtros.Web Panels Para exibir múltiplos registros: Grid (sem tabela base). sem código. ou a um evento de usuário. 4 Refresh não é automático! Agregamos botão associado ao evento Enter ou de usuário. ou diretamente ao Refresh. No caso de um grid sem tabela base. para que o servidor volte a carregar a web panel. devido ao fato que somente precisamos dele para que um Refresh seja realizado.. GeneXus não sabe que tem que voltar a carregar o grid. ou seja. Sobre os eventos disponíveis e a ordem em que são disparados. os filtros dos dados são programados dentro do código implementado para carga (o do Load). entraremos em seguida. por exemplo. Isto é.

. de duas maneiras diferentes: 1. ou associando o evento Enter ou o Refresh. tomar una ação. 2. em cada execução da web panel (como o Start. IsValid. Refresh. etc. Em nosso wiki tem informação detalhada. Drop. drag. drop. TrackContext).). Load).click … Endevent Com esta última alternativa não teremos que definir um evento de usuário. assim como no Help de GeneXus. Alguns ocorrem sempre. IsValid. Sobre os eventos associados as ações sobre os controles (click. etc..) e nesse caso disparar este evento baseado ao valor modificado. (quando fizer duplo clique. e definindo um evento de usuário na propriedade OnClickEvent. Editando as propriedades do controle (F4). O mesmo ocorre com os eventos DblClick. Drag. DblClick.) não veremos no curso presente. Sobre o evento TrackContext somente mencionaremos que é possível detectar mudanças no valor de um dado controle (grid. mas sim teremos que programar o evento click do controle. quase todos os controles que aparecem no form brindam a possibilidade de disparar um evento quanto o usuário faz clic com o mouse (os hiper-links aparecem em execução). Assim mesmo. etc. de Usuário: Através da propriedade OnClickEvent podem Estar associados a controles do form Em toda Web panel existem eventos do sistema que podem ser programados. botão direito. Enter. RightClick. dblclick. 348 . variável. RightClick.Web Panels Programação dirigida por Eventos • • • • • • Evento Start Evento Refresh Evento Load Evento Enter Eventos de Usuário Evento TrackContext (no curso não será visto) • Associados a controles do form (dependendo do tipo de controle): • Evento Click. Dando um nome ao controle e na seção de Eventos programando: Event nomeControl. Nota: Refresh. outros se forem declarados e o usuários realiza as ações necessárias para provocá-los (Enter. definidos pelo usuário. etc.

Visible =0 &Update = LoadBitmap("images/edit. etc. • Os valores de atributos não são conhecidos.: Event Start &var. Isto se deve que ainda não foi efetuado a consulta. para carregar um bitmap. para associar um Link a outro controle. • Exemplo: se pode utilizar para que um controle do form não apareça visível.Link = Tcustomer.link() endevent . exceto os recebido por parâmetro. que ocorre automaticamente sempre que se faz Get ou Post e é o primeiro evento que se executa.Web Panels Evento Start • É um evento do sistema.gif") newControl.

para realizar o mesmo (evento Load. será carregado a linha do grid e o ponteiro é passado ao seguinte registro da tabela base. carga da linha). Primeiro é executado o Refresh e depois sempre o Load. antes de efetivamente carregá-lo no grid. 350 . associados a carga da Web Panel. O controle da carga do grid. Este comando somente é válido dentro do evento com o mesmo nome. ao produzir-se o evento Refresh se acessa a base de dados. Note como no caso do grid com tabela base. Dentro desse evento a carga terá que ser codificada.. que pode ser que precise acessar a base de dados (ex: comando for each) o não (vamos supor que seq queira carregar o grid com informação obtida ao percorrer um SDT collection. fica aquí nas mãos do analista. Vai ocorrer nesse processo um evento Load para cada registro em que estiver posicionado. este comando não é necessário. Quando a web panel é com tabela base. e se percorre carregando os registros que cumpram as condições (conditions do grid e gerais). somente que o evento Load é executado uma única vez. a essa tabela base (associada a web panel).. efetuar alguma transformação sobre seus itens .Web Panels Evento Refresh – Evento Load • Eventos do sistema. • Se o grid tem tabela base Load é executado N vezes: Um para cada linha • Se o grid não tem tabla base Load é executado somente 1 vez: Dentro do evento a carga da linha do grid terá que ser programada. Isto nos permite realizar alguma operação que requeira desse registro ( e de sua estendida). visto que não estará posicionado em nenhum registro de nenhuma tabela. Imediatamente depois de executado o código associado ao evento Load. Para carregar. utilizando o comando Load. Este processo se repetirá até carregar todas as linhas do grid. comando Load. ou carregar linhas no grid produto de cálculos). codificáveis. imediatamente antes de carregá-lo. Se uma web panel é sem tabela base. Neste caso no form somente aparecem variáveis (e não atributos) e também vão ocorrer os eventos Refresh e Load. GeneXus não pode determinar automaticamente uma tabela da base de dados a percorrer para mostrar a informação que se apresenta no form.

este evento NÃO se executa. se executa este evento e atualiza imediatamente depois a página.Web Panels Refresh automático • Válido somente para Grid com tabela base • Para Grid sem tabela base necessariamente tem que associar evento A propriedade Automatic Refresh que se encontra a nível da Web Panel pode tomar os seguintes valores: • When variáveis in conditions change (valor por default): automaticamente provocam o refresh. ainda que esteja programado). • Ao pressionar a tecla Enter. o usuário deve realizar uma ação: Se o grid é com tabela base: • As alterações nas variáveis dos filtros se detectam automaticamente. Se o evento for o Enter. imediatamente depois de alterar o valor de uma variável das conditions do grid. se dispara o Refresh da página (não o código do evento Enter. 351 . Se o grid é sem tabela base: • As alterações nas variáveis dos filtros NÃO se detectam automaticamente • O usuário deve fazer click no botão ou na imagem associados a um evento Refresh ou a um evento de usuário que chame um Refresh. • No: para que o conteúdo do grid se renove depois de alterar os filtros. • Ao fazer click num botão ou numa imagem associados a um evento de usuário. se dispara o evento Load carregando-se o grid segundo os novos valores das variáveis.

. dblclick.Web Panels Eventos – Ordem de disparo • GET: Quando a Web Panel é aberta. 352 . 1a. • • • Start Refresh Load • POST: As outras execuções da web panel. Acima mostramos com exemplos o caso geral. existe uma exceção. Este é o caso geral. que produziu post) Refresh Load Os eventos disparados e sua ordem depende se a web panel está sendo aberta (Get) ou se já estava aberta e está efetuando uma ação posterior a um botão (Post). vez: Start + Refresh + Load N-ésima vez: Start + Leitura de variáveis da tela + Evento que produziu o Post + Refresh + Load.. • • • • • Start Leitura de variáveis na tela Evento enter ou de usuário (click.... etc.

então por performance. e reduzindo a quantidade de dados que viajam de um lado a outro. • Exemplo: um evento que altera o estado de um controle. Por exemplo. como código javascript. Para o programador é transparente Internamente GeneXus determina as entradas e saídas de cada evento. se encontra alguma das saídas do evento Start (do server).Visible = 0 endevent • GeneXus tem inteligência para determinar. Se em suas entradas. então o evento de usuário se executará no Server. De todas as maneiras o analista GeneXus não deve se preocupar com estes assuntos. então o evento se executará no Server. Event ‘UserEvent’ &CustomerId. • Evitando roundtrips desnecessários ao servidor. não precisa ser executado no server. Refesh e Load). se entre as entradas de um evento de usuário X. 353 .Web Panels Eventos – Ordem de disparo • Exceção: • Alguns eventos de usuário devem ser executado no Server mas outros não são executados somente no Cliente (todos os outros eventos não precisam ser executados no server: Start. Se o código do evento não requer que seja executado no servidor. visto que em todo caso será o GeneXus que terá a inteligência de resolver onde vai executar o evento. se requerem de ações executas no Server. será executado no cliente.

Os atributos que se inclui nos eventos fora de comandos for each. No nosso caso. Quando uma web panel contem mais de um grid em seu form. e outro que mostra faturas. de tal maneira que quando o usuário seleciona um cliente. ocultos/hidden) • Os referenciados na Order e Conditions locais do grid A diferença do que acontecia para uma web panel com somente um grid. também queremos que vá para o cliente selecionado (e não para todos os clientes). mas sim uma tabela base associada a cada grid. totalizadas por dia. mas deverão pertencer a tabela estendida de algum (para que seja possível inferir seus valores). Atributos que participam na determinação da tabela base de cada grid: • Os incluídos no grid (são levados em consideração os atributos visíveis como os não visíveis. se mostra na listagem de navegação resultante. Os atributos utilizados nos eventos da web panel tampouco participam na determinação da tabela base de nenhum dos grids. queremos além disso relacionar os dados.Caso isso não seja respeitado. 354 . no caso de múltiplos grids os atributos da parte fixa da web panel não participam na determinação da tabela base de nenhum deles. deverão pertencer a tabela estendida de algum dos grids (da mesma forma como da parte fixa). ao especificar a web panel.Web Panels Múltiplos grids – Grids paralelos filtrar faturas por dia do cliente Aqui apresentaremos um exemplo que reúne os dois casos que viemos estudando: a web panel mostrada em execução tem dois grids paralelos: um que mostra informação dos clientes do sistema. Incluso ao estabelecer filtros de datas. GeneXus não determina uma única tabela base associada para web panel. um warning advertindo desta situação. sejam mostradas somente as faturas desse cliente.

. Assim mesmo precisa obrigatoriamente colocar essa variável no form para que tudo funcione corretamente .. com variáveis no primeiro grid e tendo que realizar a carga dos clientes a mão no Load. e na análise abaixo encontraremos a razão.. Acima podemos ver a web panel que temos o grid com os grids..Load for each order InvoiceDate where InvoiceDate >= &startDate when.. certa lógica precisa ser agregada. e atributos no segundo grid. 355 . O importante é...Visible = 0 endevent Event ‘Select customer’ &CustomerId = CustomerId endevent GeneXus não relaciona as cargas Event inoicesGrid. Mas não basta simplesmente unir as duas web panels. sendo um grid com tabela base. where CustomerId = &customerId when not &customerId. Em qualquer dos casos..IsEmpty() . agregamos a parte de visualização de faturas por data que implementamos na web panel. como esperamos. para poder relacionar as cargas dos grids. e depois agregar um filtro pelo valor dessa variável quando se carrega o grid de Invoices. as faturas carregadas no segundo grid não sejam de todos os clientes. É análogo o caso de um par de for eachs paralelos no Source de um procedimento.. mas somente do selecionado.. Acima podemos ver a implementação mais natural: o primeiro grid tem tabela base e o segundo não tem. e algumas coisas a mais para obter o controle de corte. Ou qualquer combinação (ambos grids com tabela base. realizá-la corretamente. Em nosso caso desejamos que uma vez um cliente for selecionado no primeiro grid.. GeneXus não assume nenhuma relação entre os dados na hora de carregar um grid e o outro.. ainda que a informação a ser carregada em mais de um grid se encontre relacionada na base de dados. ou nenhum com tabela base). uma vez escolhida a implementação mais natural ao caso. where InvoiceDate <= &endDate when. a lógica deve ser agregada. Em nosso caso desejamos que uma vez que selecionarmos um cliente do primeiro grid. endevent Esta web panel poderia ter sido implementada de diferentes formas e obtendo o mesmo resultado na execução. Mas poderia ter sido implementada de forma contrária.Web Panels Múltiplos grids – Grids paralelos Event Start &CustomerId. Para isso devemos ter duas coisas: agregar uma variável &CustomerId para armazenar o id do cliente selecionado ao pressionar ‘Select customer’.

Observe que nosso caso.Load customerGrid. mas como já vimos. o evento Load era executado um for each com cláusulas where. Primeiro o evento Start é executado.IsEmpty()) O segundo grid é sem tabela base. de todos os clientes. não são aplicadas se estiverem vazias (visto que ambas cláusulas condicionais tem when not &var. Podemos ver na imagem. 356 .Load Vamos analisar o que acontece quando a web panel é executada pela primeira vez. serão carregadas somente aquelas linhas que as condições são cumpridas.Load . oculta &customerId invoicesGrid. Um evento Refresh próprio ocorre e o evento Load (se possuir tabela base são N vezes e se não tiver tabela base somente 1 vez)..IsEmpty() where CustomerId = &customerId when not &customerId. São três: where InvoiceDate >= &startDate when not &startDate.IsEmpty() Observe que nesta primeira execução &customerId está vazio. o grid de cliente tem condições para serem carregadas. que um evento Refresh genérico é produzido. depois serão produzidos as cargas de todos e cada um dos grids encontrados na web panel. o filtro não é aplicado e todas as faturas do dia é carregada.Refresh customerGrid. execução Start Refresh customerGrid. da esquerda para a direita de cima para baixo.Web Panels Múltiplos grids – Grids paralelos 1ª.Refresh invoicesGrid.. em nosso caso a variável &CustomerId é ocultada.. pelas variáveis de filtro &customerName e &countryName.IsEmpty() where InvoiceDate <= &endDate when not &endDate.

se não estiver no form e torná-la invisível. O segundo. quem executa o Start (ocultando a variável). Depois ocorre o evento Refresh geral que dispara o Refresh e Load de cada grid. pode ser visto facilmente que teríamos o mesmo comportamento se somente fosse atribuído valor a variável no ‘Select Customer’ sem colocá-la no form.. Simplesmente porque não se pode usar como variável dentro do programa.. as que são definidas. Aqui a variável &customerId toma o valor do CustomerId da linha escolhida. são consideradas não somente as variáveis da tela. agora se tiver um valor para &customerId. entre ela. Uma ação é detectada e ocorre um post ao servidor.. mas também a informação completa da linha selecionada pelo usuário com o mouse. invoicesGrid. depois o código do evento que produziu o post é executado.Refresh invoicesGrid. Todavia com esta segunda execução não podemos responder a pergunta.Web Panels Múltiplos grids – Grids paralelos 2ª.Load . De fato.Load customerGrid. porque nenhuma de suas conditions variou. 357 . Vamos ver o motivo com a execução seguinte.. Você poderia se perguntar porque precise colocar a variável oculta no form. no nosso caso. Portanto. execução Selecionar um cliente: Start oculta &customerId Leitura das variáveis na tela Evento que produziu o post Event ‘Select customer’ &CustomerId = CustomerId endevent Refresh customerGrid. se analisarmos. coluna do grid).Load O usuário seleciona o cliente do grid o cliente correspondente da linha e pressiona o botão ‘Select customer’. O primeiro se carregado como antes. depois as variáveis da tela são lidas (&customerId no momento está vazia. somente será mostrado as faturas do cliente. cada grid é executado executando as conditions. ‘Select customer’.Refresh customerGrid... o valor de CustomerId.

o botão ‘Select Customer’ poderíamos chamar ‘Select/Unselect’. Para isso especifica os filtros de data.. agora aparece somente as faturas do segundo cliente.Refresh customerGrid. e o que deseja fazer é filtrar suas faturas por data (não quer visualizar todas). Lembre que cada vez que se faz um post ao servidor. O valor da variável &CustomerId fica vazio. Alterando as condições do for each que carrega o segundo grid.Load . para ver suas faturas. invoicesGrid.Load customerGrid. é a forma de manter a memória em execuções. Por isso que o segundo passo: “Leitura de variáveis da tela” é fundamental. será feito a seleção no grid de clientes e ao pressionar ‘Select Customer’. Então o código do Start é executado.Refresh invoicesGrid. permanecendo até que o usuário não selecione outro cliente do grid e pressionar o botão ‘Select customer’. o processo começa novamente como vimos na 2da. entre as datas estipuladas pelo usuário. esta variável presente no form.. já que as variáveis começam novamente vazias. e pressiona o botão ‘Search’.Load Agora o usuário já selecionou o segundo cliente. que produzirá um post no servidor. a carga é executada (Refresh genérico + Refresh e Load de cada grid).. 358 . E como fazemos para voltar a trabalhar com as faturas de todos os clientes e não de um? O que acontece se o usuário não selecionar nenhum cliente do grid com o mouse e pressionar ‘Select Customer’... é uma nova execução da web panel. pois CustomerId não vai ter valor. depois são lidas as variáveis da tela: aqui está o motivo de ter colocado &customerId no form. seguindo o exemplo. como sempre. Por este motivo. junto com as variáveis &startDate e &endDate. execução. Se agora o usuário quiser alterar o cliente. O valor de &customerId é lido. as variáveis da tela são lidas &customerId invisível (visible=0). execução Filtrar as faturas para o cliente selecionado Start Leitura das variáveis na tela &customerId invisible Evento que produziu o post (vazio) Refresh customerGrid.Web Panels Múltiplos grids – Grids paralelos 3ª. Agora sim. E depois.

Web Panels Grid .Propriedades • Paginação automática: Se a propriedade Rows possuir um valor diferente de 0 GeneXus realiza a paginação automática Insere os botões de paginação de forma automática Os botões inseridos dependem da quantidade de registros e da quantidade de linhas do grid. 359 .

Web Panels Grid – Ordem automática das colunas Não é necessário programar nenhum código adicional para ordenar as colunas: clique sobre o título da coluna. A página do grid carregado é ordenado. Esta funcionalidade é válida para grids em transações e web panels. mas não compete com o Order programado no grid. 360 .

No exemplo apresentado acima queremos mostrar alguma informação dos países. Novamente este comportamento pode ser modificado. imagens. ou se associa um evento a qualquer controle da fila. botões. O atributo CountryFlag foi incluído na transação “Country” para armazenar a foto da bandeira de cada país (é um atributo de tipo Blob). • Tabela com registros repetitivos • As colunas não possuem títulos • Permite ter mais de um tipo de controle numa mesma célula Dois tipos de grid: • Grid padrão: que vimos até agora. O grid Freestyle é basicamente uma tabela que podem inserir os atributos/variáveis. em Transações e Web Panels • Grid Free Style Estes grids. text blocks. agregando a regra noaccept ou alterando a propriedade Read Only. Neste caso para poder visualizar as propriedades tem que selecionar a tabela onde se encontram os atributos/variáveis. cada elemento de informação em uma coluna diferente do grid. agregam potência ao desenho de aplicações web. grids freestyle e/ou grids que serão mostrados posteriormente na tela. web components. permitindo ao desenvolvedor maior liberdade na hora do desenho.Web Panels Tipos de grids • Grid stardand: Dados repetitivos no formato fixo (filas e colunas) • Grid Free Style: Dados repetitivos em formato livre. O comportamento das variáveis dentro de um grid Free Style é análogo ao apresentado dentro de um grid padrão. embedded pages. 361 . Aqui queremos mostrar a foto e abaixo o identificador e nome do país. Mas não queremos mostrar a informação como o faríamos em um grid padrão. O grid Free Style permite ao usuário definir o formato dos dados a serem mostrados de uma forma menos estruturada que o grid padrão. portanto também são de ingresso se existe um For each line ou For each line in <grid> dentro de algum evento.

Web Panels Múltiplos grids – Grids aninhados Exemplo: Mostrar todos os países com seus respectivos clientes..Load carga de cliente do país Grid2..Load carga do país seguinte Grid2. aqui as cargas estão relacionadas.Load carga de um país Grid2.Load carga de cliente do país Grid1.Load carga de cliente do país Grid2.Load carga de cliente do país Grid2. { CountryId* CountryName CountryFlag Grid2: standard } Trn Customer Tabela base Grid1: COUNTRY Tabela base Grid2: CUSTOMER { CustomerId* CustomerName CustomerAddress CountryId CountryName } Este caso de grids aninhados é igual o de for each aninhados em um procedimento: ou seja.Load carga de cliente do país . e no Grid2 é carregado todos os clientes pertencentes ao país carregado no Grid1... Trn Country Grid1: Free Style.Refresh Grid1.Refresh Grid2.Load carga de cliente do país Grid2. e quantidade de clientes. 362 . A ordem de execução dos eventos estará aninhada: Refresh (genérico) Grid1.Refresh Grid2.

Web Panels Grid Free Style (Exemplo: Continuação) Propriedades Grid Free Style 363 .

“Master Page” e sua utilização. 364 .Web Panels Tipos • Tipos de Web panels • Component • Web Page • Master Page • Propriedade Type Os objetos web podem ser definidos com três tipos diferentes. que a partir daqui poderá ser incluído em outro web object) • Web Page (isto é. Para uma web panel poderá ter um dos valores: • Component: (transação ou web panel. o objeto será uma transação ou web panel tal como temos trabalhado até o momento) • Master Page Em seguida introduziremos a Web Panel tipo: Component”. configurável na propriedade Type do objeto.

Web Panel Web Component Já programamos uma web panel ‘CustomerView’ que mostrava os dados do cliente vamos reutilizar Um component é uma web panel que é executada dentro de outra. 365 .

Web Panels Web Component 366 .

Web Panels Web Components Exemplo: Criar um novo tab na instância do Pattern Work ‘With Countries. 367 . 1) Definir a Web Panel CustomersPerCountry como Component 2) Definir o novo tab CustomersPerCountry na instância do Pattern Work With Countries A Web Panel CustomersPerCountry recebe CountryId como parâmetro. mostrando os clientes de cada país.

Web Panels Web Components 368 .

e no mesmo se deixa um espaço para carregar a página correspondente (o conteúdo variável do site). Criar e manter cada página de uma aplicação Web assegurando a consistência com o resto do site leva grande tempo de programação. Isto significa que a modificação de alguma parte do layout ou do comportamento comum é tão fácil como modificá-la num único objeto e pronto!. Agora faça o seguinte.Web Panels Master Pages As Master Pages fornecem uma forma de centralizar o layout e o comportamento comum em um objeto e reutilizá-lo em qualquer objeto. As páginas web que implementam o conteúdo variável. AppMasterPager categorizado como “Master Page” será criada com tudo. são carregadas com esse “contexto”. se implementam como Web Panels ou Web Transactions comuns e correntes (é do tipo “Web Page”. o Layout e comportamento comum a todas as páginas do site. e se associam a Master Page. de maneira que cada vez que se executem. ver página anterior). e veja o valor da propriedade Master Page. Ao criar uma base de conhecimento GeneXus X criará também dois objetos de tipo Mastet Page: • ApplMasterPage: Para a aplicação • PromptMasterPage: Para os prompts Uma web panel. isso sem termos que programar. Corresponde ao controle especial ContentPlaceholder. ou seja. Em uma mesma base de conhecimento podem ser definidas tantas Master Pages quanto desejar. 369 . abra qualquer objeto GeneXus com form (transação ou web panel) criada na KB. As Master Pages fornecem uma forma de centralizar o layout e o comportamento comum em somente um objeto e reutilizá-lo em todo outro objeto sem ter que programar. Controle onde as páginas serão carregadas Criadas automaticamente com a KB Ter um look&feel consistente é hoje em dia um dever de toda aplicação Web.

GXFLOW .

que define um processo no qual as situações são resolvidas manualmente ou automaticamente. • Exemplo No exemplo se está mostrando um workflow de uma empresa que vende mercadoria “por atacado”.GXFLOW Breve introdução teórica • O que é um workflow? Um conjunto de tarefas ordenadas em determinada sequencia. . Podem ser observados claramente as tarefas consecutivas seguintes para fazer o processo de venda.

GXFLOW
Breve introdução teórica

• Por que recomendamos incluir tecnologia de workflow dentro de nossas soluções GX? Porque todo sistema que quisermos construir para uma empresa, 99% terá processos de negócios para modelar, gerenciar e dar seguimento … - conjuntos de tarefas ordenadas - responsáveis - cronogramas, alertas, tempos máximos ... e gerenciar e dar seguimento: Gxflow faz

GXFLOW
Breve introdução teórica

Gxflow é uma ferramenta integrada a GeneXus que nos permite:
• • • • • • • Modelar os processos da empresa Definir segurança Definir calendários, alertas, deadlines Etapas de integradas Modelado e Desenvolvimento da aplicação operacional

Etapa de execução que brinda pro-atividade Auditoria Clareza para capacitar membros novos e para mostrar aos clientes

Gxflow é uma ferramenta integrada ao GeneXus que nos permite e brinda: 1) Modelar os processos da empresa: Diagramar os processos nos da vantagem de poder mudar a ordem de suas tarefas, tirar ou incluir tarefas novas e/ou mudar as condições de sua execução, sem tocar o código dos mesmos objetos. 2) Definir segurança: Se definem regras e quais podem executar quais tarefas. Isto evita ter que incluir código para a segurança nos objetos. 3) Definir calendários, alertas, deadlines 4) Etapas de Modelado e Desenvolvimento de aplicação operacional integradas: Em GeneXus X é muito prático e simples relacionar os objetos GeneXus desenvolvidos que implementam a aplicação operacional com os diagramas que modelam os processos. Veremos como se arrastam os objetos aos diagramas e a prática resultante em ter modelado os processos integrados com o desenvolvimento da aplicação operacional. 5) Etapa de execução que brinda proatividade: Cada usuário ao executar, de primeira verá as tarefas que precisam ser feitas (não terá que buscar na aplicação o trabalho pendente). 6) Auditoria: GXflow permite ver o que está em cada usuário, quanto tempo leva cada tarefa, etc. 7) Melhor entendimento: para um membro novo da equipe de trabalho, e também para fazer mostras aos clientes.

GXFLOW
Breve introdução teórica

• Passos para trabalhar com GXflow:
• Criar objetos GeneXus que descrevem realidade e processos
INTERCALADOS

• Criar diagramas de processos de negócios para modelar os processos • Associar objetos GeneXus a diagramas de processos de negócios • Executar processo

GXFLOW
Conceitos básicos para criar diagramas de processos de negócios

Como criar um diagrama de processo de negócio? Criando um objeto na KB de tipo Business Process Diagram

Quantos diagramas de processos de negócios definiremos em nossa KB? A quantidade de processos que tenham na empresa

GXFLOW
Conceitos básicos para criar diagramas de processos de negócios

Definição passo a passo.. (1)

GXFLOW
Conceitos básicos para criar diagramas de processos de negócios

Definição passo a passo.. (2)

TAREFA / ATIVIDADE INTERATIVA

ARRASTANDO ESTES SÍMBOLOS É CONFECCIONADO O DIAGRAMA

TAMBÉM SE PODE ARRASTAR AO DIAGRAMA TAREfA / ATIVIDADE INTERATIVA A PARTIR “FOLDER VIEW”

A partir do “Folder View” se arrasta um objeto transação ou web panel ao diagrama, se estará agregando una “tarefa / atividade interativa” ao fluxo, e a mesma já ficará com dito objeto associado para a etapa de execução. Também dita “tarefa / atividade interativa” agregada ao diagrama, ficará automaticamente nominada com o mesmo nome que a transação ou web panel que foi arrastado. Por outro lado se agregar uma “tarefa/atividade interativa” ao diagrama arrastando o símbolo correspondente a partir do toolbox disponível para confeccionar diagramas de processos de negócios, depois será necessário associar a dita tarefa um objeto transação ou web panel definida na KB. Para isso, simplesmente de ter agregado a tarefa no diagrama e a tendo selecionada, terá que editar suas propriedades (F4 para abrir o diálogo de propriedades) e completar a propriedade Web Application com o objeto que corresponda, assim como a propriedade Name com o nome que se queira dar a “tarefa/atividade interativa”.

GXFLOW
Conceitos básicos para criar diagramas de processos de negócios

Descrição de símbolos

INÍCIO DE PROCESSO ATIVIDADE/TAREFA INTERATIVA ATIVIDADE/TAREFA BATCH NESTE PROCESSO QUE SE ESTÁ MODELANDO, OUTRO PROCESSO É REUTILIZÁVEL COMO SUBRPROCESSO CONDIÇÃO PARA AVALIAR… E DEPENDENDO DO RESULTADO, SEGUIRÁ UMA ROTA OU OUTRA VÁRIAS ROTAS CHEGAM ATÉ ESTE SÍMBOLO E ASSIM QUE TODAS CHEGUEM A ESTE PONTO, O FLUXO CONTINUA FIM DO PROCESSO

Não serão descritos todos os símbolos disponíveis na toolbox de workflow, mas sim os símbolos básicos que no início devemos conhecer. Símbolo: Condição Quando se está modelando um diagrama de processo e em determinada parte do fluxo de atividades se necessita avaliar uma condição porque dependendo dela ser cumprida ou não, siga com certo fluxo de atividades ou outro, por isso que contamos com o símbolo de condição.

Bastará agregar um símbolo de condição (losango verde) ao diagrama (conectado desde a atividade prévia) e a partir do losango poderão sair N rotas (que terão a cor verde também). Cada uma destas rotas verdes que partem de um losango de condição, deverá ter associada uma condição a ser avaliada (fazendo clique duplo em cada rota verde, um editor é aberto para ingressar sua condição associada); e em tempo de execução do diagrama, como veremos mais adiante, quando se chegue a condição na execução do processo, dependendo de quais avaliações for verdadeira continua com a execução de uma rota e seu fluxo de atividades segue, ou outro. Em breve veremos exemplos de definição de condições (sintaxe e possibilidades).

Símbolo: Batch Activity Permite agregar a um diagrama de processo de negócio, um processo batch (por exemplo um processo maciço) que será executado no servidor. É agregado arrastando o símbolo correspondente desde a toolbox, depois será necessário associar a dito processo batch um objeto procedimento definido na KB. Para isso, simplesmente depois de ter agregado o símbolo de processo batch no diagrama e tendo selecionado, terá que editar suas propriedades (F4 para abrir o diálogo de propriedades) e completar na propriedade Procedure o nome do procedimento que corresponda. Assim mesmo terá que atribuir um nome em sua propriedade Name. Se por outro lado a partir do “Folder View” se arrasta um determinado procedimento, estará sendo agregado ao diagrama como processo batch que executará no servidor; e o mesmo já ficará com dito procedimento e nome associado para a etapa de execução.

Temos agregado tarefas interativas e uma condição. QUE INFORMAÇÃO PODEMOS ENVOLVER NAS CONDIÇÕES? Aqui vemos que temos confeccionado o diagrama de processo que criamos. se abre o editor de condições para editar cada condição (em caso dela se cumprir uma ou outra se seguirá com certo fluxo de atividades ou outro). (3) O diagrama de processo de negócio vai sendo confeccionado. Vemos que com um duplo clique nas rotas verdes que partam da condição. Em seguida veremos o conceito de “Dados Relevantes” que é fundamental para compreender qual informação podemos envolver nas condições.. arrastando símbolos de Toolbox e objetos de Folder View …. .GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Definição passo a passo.

GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Conceito fundamental: Dados Relevantes • O conceito de “Dados Relevantes” se utiliza para manter uma área global de dados num processo Este conceito permite administrar a passagem de informação entre as tarefas e que a informação seja conhecida em todo o fluxo As “variáveis globais” podem ser vistas como são no processo • • TODO “DIAGRAMA DE PROCESSO DE NEGÓCIO” TEM UM TAB PARA A DEFINIÇÃO DE SEUS DADOS RELEVANTES .

Ou seja que ao ver num diagrama de processo um dado relevante de nome InvoiceId.mas não é um atributo. tem uma correspondência automática entre o dado relevante e o atributo PK. também existem casos que surge a necessidade de definir explicitamente outros dados relevantes. propriedades e métodos. para os dados relevantes que são definidos automaticamente com mesmo nome e tipo que as chaves primárias das transações (como neste exemplo: InvoiceId). e também veremos como definir correspondência entre dados relevantes que definiremos em um diagrama de processo e variáveis que deveremos definir nos objetos GeneXus associados as atividades do diagrama (veremos que utilizaremos tipos de dados workflow.. mas sim um “dado global” que será conhecido em todo esse diagrama de processo. A maioria de Dados Relevantes num diagrama de processo se correspondem com as chaves primárias. A sintaxe do nome de um dado relevante definido em um diagrama de processo. não devemos confundir com o atributo definido na KB. automaticamente se cria um dado relevante com o mesmo nome e mesmo tipo de dado que a chave primária da transação: NOSSO OBJETO DE TIPO “BUSINESS PROCESS MODEL” AO ARRASTAR A TRANSAÇÃO “INVOICE” AO DIAGRAMA. Em seguida veremos exemplos. AUTOMATICAMENTE ESTE DADO RELEVANTE FOI CRIADO • Também definiremos veremos... como Quando são definidos dados relevantes em um diagrama de processo (definidos automaticamente ou definidos explicitamente) algo a ser dito é que não são os mesmos atributos definidos na KB. para que variáveis “a nível de objeto” correspondam com dados relevantes definidos “a nível do diagrama de processo”). é totalmente análoga a sintaxe do nome de um atributo (e além disso tem um tipo de dados associado). Em outras palavras tem um mapa automático entre o dado relevante com o mesmo nome e tipo que um atributo chave primária com dito atributo chave primária.) • Quando se arrasta a partir do “Folder View” uma transação a um diagrama de processo. Todavia. ou no contexto do desenvolvimento da funcionalidade respectivamente). no sentido que quando modelamos o diagrama “o dado relevante é o dado global conhecido nesse contexto” e nos objetos GeneXus que desenvolvemos as atividades do diagrama “recebemos no parm o atributo PK” (tratando-se da mesma informação ou no contexto do diagrama.GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Conceito fundamental: Dados Relevantes (Cont. dados relevantes explicitamente. .

e o supervisor deverá aceitar ou recusar a venda. as quantidades. tínhamos previamente definidos alguns objetos GeneXus que arrastamos ao diagrama. a mercadoria solicitada. Por enquanto a idéia é que contamos na KB com uma transação “Invoice”. gravará a venda com um número interno (não o nro da fatura formal) e aí terminará a primeira atividade. COMO CARREGO UM VALOR OU OUTRO NESTES EVENTOS E QUE O VALOR CARREGADO “SEJA VISTO” NO DIAGRAMA PARA AVALIAR CONDIÇÃO POSTERIOR? Inicialmente explicamos que quando trabalhamos no GeneXus com workflow. Quando uma vendedora ingresse uma venda (através da transação “Invoice”). realizamos basicamente os seguintes passos: • Criar objetos GeneXus • Criar diagramas de processos de negócios • Associar objetos GeneXus a diagramas de processos de negócios • Executar processo Estamos assim confeccionando um diagrama de processo em nossa KB. e vamos desenvolvendo outros objetos e incorporá-los ao diagrama também. a web panel “Authorization” implementa a 2da atividade do processo e recebe por parâmetro o atributo InvoiceId. Então. E no que se refere aos objetos GeneXus relacionados ao diagrama. Esta segunda atividade interativa do processo foi agregada ao diagrama arrastando a web panel “Authorization”.GXFLOW Conceitos básicos para criar diagramas de processos de negócios InvoiceId = Dado Relevante no diagrama • Quando surge a necessidade de definir dados relevantes? Trn “Invoice” Web thor l “Au Pan e on” izati Parm(InvoiceId). a forma de pagamento solicitada pelo cliente. Esta web panel oferecerá ao supervisor 2 botões: “Authorize” e “Refuse”. Mais adiante veremos como atribuir regras as diferentes atividades do diagrama. Depois essa venda deverá ser avaliada por um supervisor (quem vai avaliar de qual cliente se trata. a qual foi arrastada ao diagrama como primeira atividade interativa do processo e mais adiante definiremos que esta tarefa interativa poderá ser executada pelas vendedoras da empresa. a forma de pagamento). o montante. a nível do diagrama de processo contamos com o dado relevante InvoiceId (com o mesmo nome e tipo de dado que o atributo InvoiceId). . entrará o cliente. o limite de crédito e o saldo do limite de crédito do cliente e possibilita ter o histórico das faturas anteriores do cliente. No form da web panel “Authorization” serão visualizados os dados da fatura. o qual significa que dito dado se conhece ao longo de todo o fluxo de atividades.

Assim é que são recebidos por parâmetro os atributos chaves primárias que são análogas aos dados relevantes no diagrama de processo (e que tem uma correspondência entre esses conceitos). fazemos no diagrama de processo sem tocar o código dos objetos no diagrama de processo. e se foram definidas. Se nosso objetivo é carregar uma variável com valor 1 no evento “Authorize” e com valor 0 no evento “Refuse”. que mostra em seu form informação para a tomada de decisão da autorização ou recusa e para isso tem 2 botões “Authorize” e “Refuse” respectivamente. Mais adiante veremos que na etapa de execução vamos executar uma aplicação que nos permite criar instancias dos processo que definimos (por exemplo poderão ser criadas N instancias do processo de venda definido). de tipo de dados: WorkflowProcessInstance . assim: Sendo: &wfAuthoriz: uma variável definida na web panel. De modo que não codificamos mais calls nos objetos GeneXus.Vale explicar que quando trabalhamos com workflow em GeneXus. que em nosso exemplo é um supervisor) e assim sucessivamente e as atividades da instancia do processo vão sendo finalizadas e executando as seguintes atividades até concluir dita instancia do processo. no código dos objetos já não podemos chamar de um objeto a outro. seguirá a segunda atividade (para ser efetuada por ele rol que corresponda... se definimos a regra parm nos objetos GeneXus que participam num diagrama de processo. ou agregar ou tirar atividades. e caso se necessite mudar a ordem de precedências das atividades em um processo. 2) Na web panel "Authorization“ terá que ler o dado relevante e carregá-lo em cada evento da web panel. será validado que em particular essa atividade seja realizada por uma vendedora. começa a execução da primeira atividade (será mostrada a trn “Invoice” para isso. Algo que se deve notar é que não definimos calls no código mesmo dos objetos. e queremos que o valor atribuído “seja visto” no diagrama de processo. Agora que isso foi explicado. precisa criar um dado relevante (por exemplo de nome: InvoiceAuthorized) de tipo Numeric. nos diagramas de processos que confeccionamos já ficam implícitas as chamadas entre atividades consecutivas. assim como mudar as condições de execução das atividades. Isto é porque os objetos são chamados – com outro esquema de trabalho do que conhecíamos – e precisa passar a informação necessária . seguiremos estudando passo a passo a implementação da segunda atividade do processo que estamos confeccionando. de tipo de dados é: WorkflowApplicationData &wfProcessInstance: uma variável definida na web panel. Por outro lado. Ao criar uma nova instancia de processo. mas definimos regra parm nos objetos. A web panel “Authorization” recebe por parâmetro o atributo InvoiceId. bastará realizar o seguinte: 1) No tab “Relevant Data” do diagrama de processo.

estamos recuperando na variável &wfAuthoriz (de tipo “dado relevante”) o valor do dado relevante de nome ‘InvoiceAuthorized’ (entre aspas vai o nome do dado relevante tal como foi definido no diagrama de processo) pertencente a instancia do processo que está sendo executado. O tipo de dados WorkflowApplicationData significa “dado relevante”. Depois na segunda linha codificada em ambos eventos. Também temos definido na web panel uma segunda variável de tipo WorkflowProcessInstance. Desta maneira então lemos e carregamos dados relevantes nos objetos GeneXus associados as atividades de um diagrama de processo (exceto quando se trata de dados relevantes com mesmo nome e tipo que as chaves primárias. (4) Criação explícita de Dado Relevante no Diagrama de Processo e como trabalhar com o mesmo nos objetos 1) 2) Em wbp “Authorization” definimos 2 variáveis de tipos de dados WorkflowApplicationData e WorkflowProcessInstance para ler e carregar o dado relevante Vimos que definimos um dado relevante no diagrama de processo (de nome InvoiceAuthorized) e depois na web panel “Authorization” se lê o dado relevante na variável &wfAuthoriz de tipo WorkflowApplicationData. se foi carregado o valor desejado e se deseja culminar com a execução desta atividade.. Ou seja se analisarmos a primeira linha codificada dos 2 eventos. . se está atribuindo a variável &wfAuthoriz (de tipo “dado relevante”) o valor 0 ou 1 segunda corresponda (utilizando a propriedade Numeric do tipo de dado WorkflowApplicationData. já que nesses casos são recebidos por parm os atributos primários diretamente e pronto). porque já foi recuperado o valor do dado relevante.GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Definição passo a passo. Por último em cada evento se faz return. por estar atribuindo um valor numérico). O tipo de dados WorkflowProcessInstance significa “instancia de processo”.

. (5) Avaliação de Dado Relevante em condição de Diagrama de Processo Em todo o diagrama contamos com o Dado Relevante InvoiceAuthorized.. Em rotas que saem da condição Se avalia o valor do dado Relevante InvoiceAuthorized… ..GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Definição passo a passo.

e avaliar diretamente atributos.. que grava 1 ou 0 no atributo InvoiceAuthorized da invoice autorizada/recusada No Diagrama de Processo o atributo InvoiceAuthorized pode ser inferido (através de Dado Relevante InvoiceId que corresponde ao atributo InvoiceId) a avaliamos diretamente dito atributo 3) AVALIAMOS ATRIBUTO (NÃO DADO RELEVANTE) Com esta solução. já que temos num atributo a informação se a invoice foi autorizada/recusada… e no fluxo podem ser inferidos atributos através dos Dados Relevantes correspondentes a chaves primárias. não temos necessidade de definir Dado Relevante InvoiceAuthorized. .GXFLOW Conceitos básicos para criar diagramas de processos de negócios • 1) Outra solução possível para resolver passos (4) e (5) Se quiser definir atributo InvoiceAuthorized na trn “Invoice” e gravar em cada invoice autorizado ou não. se foi 2) Na web panel “Authorization” se chama proc em cada evento.

. na propriedade Roles poderá atribuir a lista de regras que dita atividade poderá executar.GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Definição de regras DEFINIÇÃO DE REGRAS NA KB 1) 2) ATRIBUIÇÃO DE REGRAS DAS ATIVIDADES NO DIAGRAMA A definição de regras a nível da KB na seção de Preferences. Depois selecionando cada atividade do diagrama e pressionando F4.

a seguinte atividade no diagrama é “InvoiceToBePrepared”. mostra a informação da venda autorizada e tem um botão para que a pessoa do pacote quando terminar de preparar a mercadoria o pressione. mostra a informação da venda preparada e tem um botão para emitir a fatura. ficarão registradas durante a execução do workflow. um valor indicador (flag) de que o pacote já foi realizado. uma proc grava que a mesma foi entregue. O evento associado a esse botão.GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Diagrama de Processo completo correspondente ao processo que estamos confeccionando: Se o supervisor autoriza uma venda. Esta atividade interativa tem uma web panel associada que recebe por parâmetro o atributo InvoiceId. Esta atividade também tem uma web panel associada que mostra os dados da venda e pressionando um botão. o evento associado ao botão chama um procedimento que grava na invoice o número de fatura formal e emitirá a impressão. A última atividade deste fluxo que estamos explicando. vai chamar um procedimento que gravará num atributo da invoice. . As datas/horários que foram efetuadas cada uma das atividades. Quando uma vendedora pressionar este botão. A seguinte atividade é interativa e tem uma panel associada que recebe por parâmetro o atributo InvoiceId. corresponde a distribuição da mercadoria.

GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Passos para executar: • • • • Save All Build All (Serão solicitados dados de Enviroment) Run do Diagrama de Processo .

Na etapa de prototipação não nos interessa testar a segurança. não se aborta nada inicialmente e se requer criar usuários (para login) cada um deles com a lista de regras que o corresponda. já que neste caso a segurança é controlada. E a modalidade “FullClient” a etapa de produção.GXFLOW Conceitos básicos para criar diagramas de processos de negócios • Execução: Tem 2 modalidades de execução: • Prototyper • Full Client Na seção de Preferences se configura a desejada: Logicamente a modalidade “Prototyper” está orientada a etapa de prototipação. . Ao executar a aplicação na modalidade “Full-Client”. motivo pelo qual ao executar a aplicação na modalidade “Prototyper” inicialmente são limpas todas as instancias de testes anteriores e é permitido executar todas as atividades sem controlar regras.

GERÊNCIA DE VERSÕES .

O que aconteceu com a regra da semana passada? A aplicação em execução não é compatível com o código fonte Realmente estamos trabalhando na última versão? Não pode reproduzir o error nesta versão! Este programa ontem funcionava! .Gerência de Versões O desenvolvimento de software é um trabalho em equipe e certo grau de confusão é inevitável.

é necessário marcar marcos no desenvolvimento da mesma. entendendo como marcos o “congelamento” do desenvolvimento num determinado momento especial no processo. . Além disso também vamos querer ter diferentes linhas de desenvolvimento da aplicação. .Gerência de Versões Conclusão: • O ciclo de desenvolvimento é um processo dinâmico que requer controle das alterações realizados aos objetos do projeto. O que necessitamos basicamente é administrar o “ciclo de vida” da aplicação durante o desenvolvimento. a necessidade de congelar um determinado estado especial da aplicação. Isto pode acontecer por exemplo para liberar uma versão na produção. congelar uma versão entregue a um cliente. etc. algo muito comum por exemplo quando se quer fazer variações do projeto para um cliente ou quando se requer que dois grupos de trabalho o façam em paralelo e necessitamos poder realizar uma administração de todos estes elementos. Se necessita: • Marcar marcos no desenvolvimento da aplicação • Ter linhas de desenvolvimento paralelas • Administrar o ciclo de vida da aplicação (SCM) . Várias destas funcionalidades entram no que no mundo do software se conhece como SCM (Software Configuración Management) . KB Versão 1 Versão 2 Versão N Durante o processo de construção da aplicação.

1. a principal vem a ser o que se conhece como Trunk e as demais seriam o que em SCM se conhece como Branches •Frozen Versions (também conhecidas como Labels em SCM). seja pela liberação de uma versão. entrega ao cliente. seja pela determinação de checkpoints como a necessidade de abrir novas linhas de desenvolvimento. Para isso se introduz o conceito de Gerência de Versões.1 Nó raiz da árvore de versões 1.0 sem afetar a linha de desenvolvimento principal que continuou crescendo desde o momento que foi congelada a versão 1. etc.0. a entrega de uma versão a um cliente. Então se cria o que se conhece como Developmen Version ou branch. Estas situações formam parte da operação normal no desenvolvimento de uma aplicação e é necessário administrar este processo de forma fácil. etc. a necessidade de congelar um determinado estado de uma aplicação.0 e assim sucessivamente até ter por exemplo a situação estabelecida no diagrama.0 2. . Em determinados momentos deste ciclo surge a necessidade de estabelecer um checkpoint no processo.1 1. As versões são classificadas em: •Development Versions. Em determinado momento surge a necessidade de realizar correções sobre a versão entregue ao cliente (1.0.0.0 que a entregamos a um cliente e continua o processo de desenvolvimento principal.0 1.Gerência de Versões Solução: Gerência de versões da aplicação 1. que é simplesmente uma nova linha de desenvolvimento paralela a principal.1.2 2.) . lugar onde são agregadas as funcionalidades requeridas e são utilizados protótipos para prová-las .0.0) sendo necessário abrir uma nova linha de desenvolvimento para incluir estas correções sobre o que era a versão 1.0.1 1.1 que vem a ser um congelamento da linha de desenvolvimento aberta a partir da versão 1. congelar estado.2 APP APP 1.1.2 Começa o desenvolvimento seguindo uma linha principal de desenvolvimento (linha do meio – Trunk).1 1. ou a 1. representam as linhas de desenvolvimento da aplicação as quais são independentes entre si. Então o que fazemos é congelar o produto nesse momento criando por exemplo a versão 1.1 1. Depois durante o transcurso do projeto voltam a aparecer requerimentos deste tipo. então por exemplo criamos a versão 1. existe uma linha principal e várias paralelas. representam as congeladas criados em determinados momentos do processo sobre as DV para determinar certos checkpoints (liberação de versão.

1 1.0.0 1.2 2.0.2 Development Version Frozen Versions .1.Gerência de Versões Solução: Gerência de versões da aplicação Development Version 1.1 Development Version (Trunk) Nó raiz da árvore de versões 1.1 1.0.0 2.1 1.1.1 1.2 APP APP 1.

0 1. O desenvolvimento em cada uma destas development version é independente.2 Nó raiz da árvore de versões = nó raiz do Trunk Development Version As development version são as linhas de desenvolvimento da aplicação.0 2. ou para liberar uma versão especial para um cliente. sua própria base de dados. Além desta linha principal poderão existir uma ou várias linhas de desenvolvimento secundárias.1. No ciclo de vida de uma aplicação participa uma linha de desenvolvimento principal.2 2.1 Development Version principal (Trunk) 1.0. uma cópia da KB editável e independente.0. é então. isto é. tendo cada versão seus próprios objetos. ambientes para gerar a aplicação. . onde começa o processo de desenvolvimento da aplicação e na qual normalmente se vai estar fazendo as modificações requeridas no avanço do projeto.Gerência de Versões Development Version 1.1 1.1 1.1.2 APP APP 1.1 1. etc. Em SCM estas linhas de desenvolvimento secundárias são conhecidas como Branches e são usadas em geral para realizar correções ou pequenas alterações sobre versões congeladas ou liberadas da aplicação. Uma Development Version. isto é o lugar onde efetivamente criamos e modificamos a aplicação.0. totalmente independentes da linha principal e independentes entre si. Em SCM esta linha de desenvolvimento é conhecida com o nome de Trunk.1 1.

1 1. como por exemplo “feche” uma versão para liberá-la aos clientes.1.1.2 Frozen Versions Uma Frozen Version permite armazenar de forma estática momentos especiais da KB. enquanto o processo de desenvolvimento continua. . “congelando-a” para obter uma “foto” num determinado momento. congelamos uma version X para se dar aos clientes.1 1.0 1. Sendo possível realizar ações relacionadas com a geração da aplicação. é uma “foto” da aplicação num dado momento. 1.0. que objetos da mesma não poderão ser modificados. Se obtêm a partir de uma versão em desenvolvimento (development version). podem ser abertos para distintas consultas ou para realizar comparações com outras versões da aplicação. Por exemplo.1 1.0 2. como por exemplo a criação da base de dados ou a geração novamente dos programas. um novo cliente requer a aplicação.2 2.0.Gerência de Versões Frozen Version: Versão não modificável. em determinado momento. É o elemento que utilizamos para marcar distintos marcos no processo.2 APP APP 1. Se os objetos não poder ser modificados. que sabemos que tem um estado correto e a instalamos ao novo cliente. então o que fazermos é gerar a mesma na version X.0.1 1. A versão obtida é Read Only.1 1. nem tampouco suas propriedades. Quando congelamos uma versão é porque determinamos que a mesma está em um estado consistente e seria conveniente guardar dito estado.

É uma Development Version criada por default quando a KB é criada. o qual se cria ao criar a KB. A aplicação vai sofrendo alterações a medida que transcorre o ciclo de desenvolvimento. a mesma vai se alterando ao longo do tempo. ou seja com a ramo principal da árvore de versões. A medida que as modificações na aplicação são realizadas.. A linha de desenvolvimento principal é onde se implementam as funcionalidades requeridas e onde se faz a prototipação.Gerência de Versões Exemplo de versões: Implementação passo a passo Variações devido a consertos ou alterações dos requerimentos Development Version “principal” (Trunk) APP APP ….Prototipado Partimos do nó raiz da árvore de versões. Esta linha de desenvolvimento geralmente coincide com o Trunk. Ciclo de desenvolvimento principal . .

Gerência de Versões Para ver a árvore de versões. abrimos a janela Knowledge Base Versions (View/Versions): Nó raiz da árvore de versões = nó raiz do Trunk .

0 As Frozen Version servem para: • Analisar (não modificar) objetos. • Como fonte de um Reporte de Análise de Impacto da base de dados • Para criar a base de dados • Para regerar todos os programas .Gerência de Versões Surge a necessidade de “congelar” versões. para fixar marcos no projeto. environments. etc. APP APP …. Para isso criamos Frozen Versions (cópia somente de leitura da aplicação).0 Frozen Version 1.0 1. propriedades. Development Version “principal” (Trunk) 1..

Gerência de Versões Como “congelamos” uma Development Version. para criar uma Frozen Version? Botão direito sobre o nó raiz do Trunk e selecionamos Freeze .

1 1. mas não se agrega funcionalidades novas. Para isso criamos uma Frozen Version 1.Como fonte ou destino de uma operation de Revert a partir de uma Frozen Version de Backup . APP APP ….Gerência de Versões Agora queremos colocar a aplicação em Produção. Development Version “principal” (Trunk) 1.Trabalhar numa linha de desenvolvimento paralela a principal . As Development Version servem para: .1 e a partir dela criamos uma Development Version “Release 1”.0 1. As mesmas são agregadas na linha de desenvolvimento principal.1 Release1 Release1 Development Version para “Produção” Na versão de “Produção” vão sendo produzidas variações devido aos consertos.0 1..

.1 como vimos anteriormente … Botão direito sobre o nó raiz e click em Freeze Frozen Version 1.Gerência de Versões Criamos a Frozen Version 1. são mostradas mais acima na árvore de versões.1 Observe que as Frozen Version mais novas.

. Development Version Release1 O tempo que se demora em criar uma nova Development Version é proporcional ao tamanho da KB.1 e selecionamos New Version.Gerência de Versões Depois com botão direito sobre a FV 1.

2 1. Ambas versões são totalmente independentes e podemos requerer congelá-las por diferentes motivos.0 1. é onde se agregam novas funcionalidades.1 1. no ciclo de desenvolvimento principal. prototipação e testing..Gerência de Versões Também podemos criar novas Frozen Versions tanto no ramo do desenvolvimento principal como no ramo de Produção.0 1. De acordo com a metodologia adotada.1. Por exemplo.1.1. é menos frequente a necessidade de criar Frozen Versions.2 1. Trunk 1. . para fixar um estado depois de certos consertos que tivemos que fazer. as alterações numa não afeta a outra. No ramo do Release1.1 1.1 1. no caso do ramo de Produção.0 2.1 1. mais certos consertos circunstanciais que não agregam funcionalidade.0 2.2 Frozen Versions de Produção Como as linhas de desenvolvimento do Trunk (Desenvolvimento) e de Relase 1 (Produção) são paralelas.2 2. alterações importantes na aplicação. É mais frequente que seja necessária “fotos” nessa etapa viva do desenvolvimento da aplicação. as alterações são menores. mas pode ser igualmente necessário. Neste caso. consertos.1 2.1 Produção Release1 Release1 1. KB1 KB1 ….1.

Gerência de Versões Observe que as Frozen Versions mais novas. são mostradas mais acima na árvores de versões .

Somente pode ter uma versão ativa por vez.Gerência de Versões Depois de certos consertos na Produção. Botão direito sobre o nó Release1 e escolhemos “Set Active” GeneXus gera automaticamente os programas e as estruturas da BD. Se pode marcar como ativa uma versão em desenvolvimento ou uma versão congelada. partindo da versão que esteja ativa. . não poderemos fazer nenhuma modificação a mesma. Para isso marcamos a DV Release 1 como ativa. nos interessa gerar a aplicação. Neste último caso. ou para comparar versões. somente utilizá-la para gerar a aplicação ou para realizar um impacto na base de dados.

será utilizada para gerar a aplicação ao fazer um Build (F5) GeneXus nos indica qual é o ramo ativo .Gerência de Versões A Development Version que estiver ativa.