You are on page 1of 136

2

GeneXus X Episode One


Cecilia Fernndez Daniel Mrquez Lisboa
Cover design: Fiorella Franzini
Artistic participation by Mara Ins Carriquiry

Preface to the 2nd Edition


Everyone at Artech has worked hard on the X version of GeneXus. This is not
just another version. It represents a great leap forward in many ways and
particularly in its capability for integration and extensions, be them by Artech
itself or by the GeneXus Community.
The Community has enthusiastically participated in the testing of CTP
versions and is currently adopting the first released version of this product. It has
put it in to work, in many cases including extensions. For the XIX GeneXus
Meeting we look forward to sharing many significant experiences in this sense.
In 2007 we asked Daniel Mrquez Lisboa (the author of GeneXus, Desarrollo
Basado en el Conocimiento Gua Prctica (Practical Guide to Knowledge
Based GeneXus Development),published by Magr in 2006) and Cecilia
Fernndez, an expert trainer in our courses, to write an introductory book on the
GeneXus Rocha Version. Now that the X version has turned into an undeniable
and significant reality, we once again have turned to Daniel y Cecilia for a second
edition of the book, with updates of that first story told as the version was under
development, to reflect the present where the X version is in full operations.
As I stated back then: "I have to admit that, at first, the books casual style took
me by surprise. Having read it attentively, I now find that the "casual style" is yet
another great idea that the authors have had" And two years later I reconfirm
my statement.

I expect this second edition to be a success, and invite all to freely access the
book, by making use of the modern technology available to us all these days, at
www.genexus.com/genexus/libroepisodio1ed2.

And

to

the

authors,

my

congratulations on their work and my sincere wish for continued success.

Breogn Gonda
Artech President

Dear Readers,
Prior to the XVII GeneXus International Meeting for users held in September
2007, we were asked to write an easily readable book on the GeneXus version that
was undergoing continuous development: the Rocha version today renamed X
-, which actually turned out to be a true re-founding of the product.
Since then, the X has been greatly enhanced, with improved and added
functionalities. Such significant advances call for the need to adapt our works
initial edition GeneXus Rocha Episode One for it to continue aimed at its
original purpose: to disclose GeneXus to those new in the discipline who may be
willing to discover this unique tool, and also to others who, having experienced
previous versions, might want to rediscover it in this new and promising stage. So
here is an updated second edition of our work. It is based on Upgrade 4 of
GeneXus X.
Artech is currently working towards the release, in just a few short months, of
GeneXus X Evolution 1, which includes novel functionalities of significance that
allow, for example, the generation of Win applications in addition to Web
applications.
We wish you enjoy reading these pages as much as we have enjoyed writing
them, and hope everyone may have the possibility of adapting their individual
pace and needs as they go through the story. Certain chapters are a little more
technical than others, particularly Chapter 3, dealing with Patterns. We finally
gave in to the temptation of revealing its full power and such enthusiasm drove us
to increasingly reveal more and more about the topic. Those of you eager to learn
more will surely read it in depth from beginning to end. Others with an interest not
as strong will probably go through it in a more superficial way. But both are
options that each reader should feel free to take. It was based on that possibility
that we unleashed our eagerness to write the story. The last chapters are probably
the ones most enjoyable to read.
To better understand the explanations, we suggest you follow the characters
steps by working yourselves on the GeneXus trial version available at
www.genexus.com/trial. Though it is possible to apply the generator and DBMS
of your choice, we recommend everyone who is new at GeneXus to select the
default ones, which coincidently are those used in the examples of the story. We
5

invite

you

to

access

our

Download

Center

(www.gxtechnical.com/genexus/libroepisodio1ed2/zip), where you may obtain a


free zip with the finished contents of the fully-developed project. Based on that
you will be able to create another project (KB) and import it. That will prove
useful in comparing the steps you follow against the already implemented
application.
Throughout the book you will find numerous quotes from a white paper by
Breogn Gonda and Nicols Jodal, titled Desarrollo basado en conocimiento.
Filosofa y fundamentos tericos de GeneXus (Knowledge-based Development.
Philosophy and Theoretical Foundation of GeneXus"), and published in May
2007.
Once again, we would like to mention our gratitude to all who contributed to
our work, each in their own personal way, during the first edition. Thank you all!
Now Mary, Diego, Mike and Julia are anxiously waiting to go on stage, so,
enjoy your reading!

The Authors
Montevideo, May 2009

Abstract
Chapter 1: The Encounter. After many years, Diego and Mary meet again and
embark on a story of encounters along with GeneXus.
Chapter 2: Once Upon a Time... There Was a Project. Julia, Mike and Diego
define and start the analysis and development of a system for a travel agency,
while Diego guides Mary, as the share coffee, through her first experience with
IDE and the creation of the projects first objects.
Chapter 3: Machine-made, Hand-finished. As Julia achieves great productivity
thanks to GeneXus patterns, Diego unleashes his creativity, and shows that
customer demands don't always translate to insurmountable obstacles.
Chapter 4: Flight to the World of Subtypes. Working at high speed, Diego
shows Mary, not at the bar but in the office this time, why Subtypes are the best
solution to problems that might arise in a data model, as he defines the final form
of the last transactions.
Chapter 5: When the "What" Is Not Enough. Mary's interest seemed to be on
the rise, as meetings, at both the office and the bar, became more frequent. A
number of questions still remained to be answered: transactions allow
declarations, but what about batch processes? GeneXus Procedures. After,
more declarations: Business Components. And How to issue pdf reports? Inviting
attractions and attractive invitations. A potential dinner. And what about, dynamic
queries, for instance?
Chapter 6: More declarations. Data Providers to allow loading and give back a
structured output, by just a declaration of intention, instead of programming.
Diego declares his intention and must send an xml to the airline.
Chapter 7: Winds of Change. At her place, he was getting increasingly agitated,
as they shared wine, music and more GeneXus. Though everything necessarily
has to come to an end, Diego was barely suspecting that this could be just the
beginning of something else.

Chapter 1

The Encounter
A man and a lady happened to ran into each other while waiting in line at the
bank. They hadnt seen each other in many years and appeared happy to meet
again. Maybe old college friends?
"Hello Mary. Its nice to see you again!! How are things going? You still
working at the same place?" asked the man in a deep, projected voice as he stared
at her with a seducing attitude.
"Hi Diego! How are you? Im doing fine, after long years in the company I was
promoted and have been working as Developer Team Manager for the past two
years, answered the lady, looking somewhat tired.
"Then I guess I should congratulate you! But, why do you look so down?
Trouble at the office? I've heard that your systems are quite trustworthy in
addition to their large scale ..."
"They are indeed, but they are also very difficult to maintain!" Mary said,
obviously upset. "I feel Im going to end up getting sick, Diego. I havent been
able to sleep well lately, and my responsibilities are far too many, not to mention
the long hours, lack of leisure time. I have this oppression in my chest..."
"Believe me, I understand" added Diego, as his right hand gently touched her
left arm. "What is your work method? Which tools do you apply?"
"Well, a bit of this and bit of that... In the end, they're all the same," Mary
answered, seemingly unaware of how close Diego was. "I have this large team
working on maintenance and development, but we can't keep up."
"Uhmm... Not all of them are the same! After were done her, would you like
to go for a cup of coffee with me so you can tell me more?" asked Diego, both
happy and embarrassed.

GeneXus?
At the coffee shop, Diego listened attentively to the problems that distressed
Mary. He remembered how strong and driven she used to be, and felt an almost
selfish pleasure in being now the one to help her out.
So as to generate an atmosphere of confidence, Diego started by asking her:
"How many projects are you working on right now?"
"Currently we have a single project in progress that involves mainly
maintenance tasks. Our clients keep asking for new things, and we are finding it
9

hard to meet their new requirements. Besides, maintenance is really expensive and
I can't justify hiring more people. It'd imply excessive overhead costs."
"Maybe the systems you use are too old, technology wise I mean... Have you
thought about reengineering everything?" he asked frivolously.
"That would be ideal, and I have suggested it actually, but we're on a really
tight schedule. And, as I said, we may have already exceeded our budget. I really
don't know what to do Diego... I'm so exhausted that I cant seem to find a way
out of this."
"I know exactly what you mean! Do you have an idea of the number of people
who are in the same situation as you? I've seen it a million times. Applications are
increasingly complex, and the manual tools we are used to do not enable
developments, or whats worse: the maintenance of such systems. They are getting
out of hand. But dont despair Mary! Theres still hope for possible solutions. The
alternative now is to automate the work done by humans, so that we can focus on
new complexities instead of coding, a task that can be accomplished by means of a
program. For instance, at my company, we're handling several large projects at
once, quite easily and without many inconveniences so far. Have you ever heard
of GeneXus?"
"GeneXus?... Oh, yes! Ive heard about it, but haven't had the time to look into
it in detail. Do you use this tool? Theyve told me that its non-technical users are
becoming more and more frequent, and that is something Ive been wondering
about."
"In fact, I'm not saying that GeneXus is the solution, but I do know that it
solves many of the problems that your company is facing. It's a program that
makes programs. It automates the creation and maintenance of your applications
and your database. Of course, as you can imagine, it's in a more abstract level than
other tools. Tell me, if you had a program that allowed you to do this
automatically, would you use it?"
"Absolutely!" she replied as she sat up straight. "Indeed, that's exactly our
problem, we have to do almost everything manually."
In Diegos opinion, the problems at Marys company were very common.
They find it impossible to take on new projects due to the time implied by the
maintenance of the current systems, based on traditional technologies. For a
software development company, this is a red flag alert.
And as for you, dear reader, by now you are probably wondering how it all
works, right?
"How does it work?" asked Mary enthusiastically.
"Wouldn't it reasonable to think that, given a set of views on data," interrupted
Diego with certain malice, "there's only one single minimum relational model for
it?"

10

"Hmmm Maybe, I'm not sure. But how is that related to my maintenance
problems?"
"And if that were true," Diego continued, as he ignored her hesitation, "don't
you think it's possible for a reverse engineering process based on those views to
create the scheme of that minimum relational database? If you need to see it to
believe it... let's make a bet, for old times' sake. Believe me, you're going to lose!"

A Bet
The objective of GeneXus is [by describing users' views] to achieve high-quality
automated management of business systems knowledge.
Breogn Gonda & Nicols Jodal

GeneXus is a tool that, starting from users' views, captures their knowledge
and systematizes it in a Knowledge Base. Using this Knowledge Base, GeneXus
automatically designs, generates and maintains the database structure and the
application programs; that is: the programs necessary for users to operate based on
their own views.

GeneXus works with pure knowledge whose validity is totally


independent from current technologies.
"GeneXus stores in a Knowledge Base all the elements needed for building the
application, and then uses the KB for developing the system, as it automatically
builds the normalized data model, also using any desired programming language
and database. This way, you can achieve a project with the company's
knowledge..."
"Oh, okay! So that allows for"

11

"Yes!" Diego interrupted eagerly in order to complete her thought, It provides


you with something very valuable, the future portability of your application. All
that knowledge business rules, dialogs, controls, reports- that is currently
expressed in specific programming languages could be perfectly translated into
other languages without the need to commence at the start line. This means that
knowledge is reused because the Knowledge Base implies knowledge that is
independent from the platform."
Following two quick blinks, and before anything else was said, Mary ordered
another round of coffee.

Knowledge Base and External and Relational Models


As the two friends went on with their conversation at the coffee shop, Mary
became more and more interested in this specific software tool and Diego in...
"On one hand, you have the Relational Model, which - as you know is meant
for obtaining an accurate representation of data in a database, upon compliance
with certain conditions that are quite desirable."
"Right!" she exclaimed, "Like eliminating redundancies and introducing a
small set of rules to avoid the most significant sources of inconsistent data."
"Exactly, rules that verify uniqueness and referential integrity, apart from
providing a set of operators for quality data management," added Diego,
enthusiastic about the complicity growing between them.
"Of course, that's why everyone uses them! Doesn't GeneXus?"
"Yep, Im getting there Remember the External Model where external views
are represented? GeneXus focuses on this model because that's where the actual
knowledge is; it's the most important model for users and developers. It includes
external knowledge and everything else, such as other auxiliary models that might
be useful, and can be automatically inferred from the External Model."
"I see... So the External Model... cannot contain physical or internal elements
like files, tables, entities, entity relationships or indexes... right?"
"Exactly! Nor any other element that can be automatically inferred," replied
Diego, eager to continue his explanation to her. "The External Model will be used
to obtain and store knowledge. It aims at representing reality in the most direct
and objective way possible."
"Sure! Its a way to independence from implementation, for you have a highlevel system description that won't change unless user views are modified. Am I
right?" Mary asked.

12

"Absolutely! That's why we take the views of the various users to be stored in
the model. Then, all the knowledge contained in them is captured and
systematized to maximize its inference capabilities."
"Actually, I find that hard
to believe. It sounds purely
theoretical. Do you mean to
tell me that a mere
description subjected to a
program
will
magically
create the application?" Mary
asked skeptically as she
expected Diego to convince
her with his passionate
reasoning.
"Well, I wouldn't call it magic; after all, we ARE talking about software here.
And you actually do have a bit of programming to do, but it's minimal. In
GeneXus you'll have certain procedural codes, but you will not be writing in the
language that you are used to. Here, you won't need to name tables, indexes or any
other physical elements in a database."
"But then... I don't understand where the Relational Model comes in," said Mary
somewhat confused.
"It's the one used to represent and handle data, the internal or physical model
that in this case you will not be creating. It will be inferred by GeneXus by means
of its reverse engineering procedure. Mine was actually a tricky bet."
"And how do you describe users' views, the External Model, to allow reverse
engineering to be applied to them in order to obtain everything you mentioned?
The description must be accurate and formal enough to avoid ambiguities and
allow a program to infer all those things that still have to do manually."
"And so it is." Diego assured her. "Descriptions are made through certain
GeneXus object types that represent the what.' Through them, GeneXus finds the
how. That's why, in order to learn to use GeneXus, you need to learn to describe
and use these object types. In fact, no profound technical knowledge is required."
Diego went on talking to fill in the reduced spaces between Marys words.
Though they hadn't seen each other for long years, he remembered Mary very
well. He was familiar with her thoughtful expression that meant he could go on
with the conversation. He couldn't believe his good luck. Thanks GeneXus! he
thought, as he continued in a slow and confidential tone, and controlling pauses so
as to achieve the desired effect.

13

"To make all this possible,


GeneXus has a Knowledge Base
initially associated with a set of
inference
mechanisms
and
certain general rules to ensure
consistency
for
instance
(referential
integrity
rules).
When the GeneXus analyst
describes reality by creating
objects, these descriptions the
External Model- are automatically systematized and stored in the Knowledge
Base. Also, from this knowledge it obtains a set of results that enhance the
accuracy of further inferences."
"It's an inference machine!" exclaimed Mary.
"Thats right! For example, given a view of the data, it can automatically infer
the program needed for handling it."
GeneXus always works based on the Knowledge Base. All the knowledge in the
Knowledge Base is equivalent to the contents of the External Model (a subgroup of the
Knowledge Base), for it consists of the External Model itself, plus independent rules
and inference mechanisms, and a set of other elements automatically inferred from it.
The developer can change the External Model by modifying objects in the user's reality.
Such modifications will be automatically transmitted to all elements where they are
necessary: other elements of the Knowledge Base, database and application programs.
Likewise, the developer may not directly change any elements that do not belong to the
External Model.
ALL the knowledge is in the External Model and this gives the possibility of later
supporting the Knowledge Base in a completely different way, while our customers'
knowledge would continue to be usable with no problems whatsoever.
Breogn Gonda & Nicols Jodal

"Diego, I will have to get going now, but I would sure like to know more about
all this. What do you say we meet again next week? Same time, same place?
"Of course," he replied, trying to sound calm and controlled.

14

Chapter 2

Once Upon a Time, There Was a Project


Travel Agency & Co., a new tourism operator, has decided to hire the services
of the software firm ACME Business Software Solutions to develop a Web. The
idea is to provide clients the possibility of searching for destinations, flights and
different services, book flights, make other travel reservations, and obtain tickets
(front-end). The project will also include the creation of a back-end system for
related data maintenance.
The ACME Company has been applying the various versions of GeneXus for
quite some time, and has several IT specialists among its staff. The team members
selected for this project are Julia, Diego and Mike. Diego and Mike are GeneXus
Analysts who work on any project assigned to them. Diego is the one specifically
in charge of developing applications and Mike takes care of the testing. Julia,
though not a GeneXus specialist, has been responsible for gathering requirements
for numerous projects, but her specific area of expertise is to document and lead
workgroup's meetings as benchmarks are achieved. In this team, every member is
entitled to express opinions and to participate in decision-making.
The preliminary tasks are done by Julia and Diego, while Mike continues
testing other applications under development for other ACME clients.
It has always been Julias method to use text processing in documenting the
work done. But in large-scale projects, it becomes quite complicated for her to
easily manage dozens of folders that imply hundreds of files, to share them with
the developers and to coordinate team discussions, among other tasks. No wonder
she was thrilled to find out that GeneXus X provided an embedded documentation
feature that would make her life easier.

Time is of the Essence


A short while ago, the companys board of directors and the development
team agreed on a short-term project that would take around three weeks. Based
on GeneXus X's well known usability and productivity features, they had
decided to reduce the time frame agreed with clients to half of the time periods
regularly scheduled.

15

"A drastic increase in productivity [system development] is still needed.


However, the productivity of programming languages has already reached
a plateau. ... So, how can we achieve this necessary increase in
productivity? With developments based on knowledge instead of on
programming. The solution is to describe instead of program!"
Breogn Gonda & Nicols Jodal

Luckily for the development team, Travel Agency & Co.'s internal operations
were quite efficient and well documented. So, Julia, Diego and Mike decided
that they would meet with people from the different company areas in order to
gather their particular views.

Every user has one or multiple views of the data he/she uses on a daily basis.
Among these views, we can identify a first group with the views used to
handle data (with restricted permits to add, modify, delete and view data).
These user views, the first GeneXus object type, are called Transactions."
Breogn Gonda & Nicols Jodal

They wanted to start representing the company's reality as soon as possible.


Among other things, they learned that Travel Agency & Co. focused on leisure
travel to a variety of destinations worldwide. What did this mean? First of all,
since destinations were tourist attractions in cities around the world, they needed
a place to store this data.
The whole team had a meeting to exchange notes and ideas, and decided that
Julia would be in charge of describing the first guidelines obtained. Meanwhile,
the others especially Diego would use GeneXus to represent the most clearly
described user views.

The IDE at a Glance


It's time to go into the GeneXus X development environment. If you like, you
can follow Julia's steps to get to know the elements that make up this environment.
That way, you'll create the project Knowledge Base and the first Transaction type
object.
Commonly known by its acronym (IDE), this Integrated Development
Environment goes way beyond its name. And that's because an IDE is an
environment that offers a high level of comfort, windows from where to select
elements, windows for writing codes, toolboxes, and source codes, among other
things. In this case, the functionality of GeneXus Xs IDE exceeds basic
requirements.
Julia opens a session in GeneXus X and sees a start page similar to the one
below:

16

Panels

Initially, we can see two clearly defined content areas. On the left is the
KnowledgeBase Navigator, offering various views. It's made up of an area (now
blank) that will display a tree with the elements of the Knowledge Base that is
open, and a set of horizontal panels with the names of other views.
On the right is a main window (that's how we will refer to it, as we'll do most
of our tasks there). It is basically another item with multiple functions. In the top
left corner of the main window is the Start Page tab, which is the first open item
in the main window. As you work, new tabs will indicate other work spaces
containing project elements such as navigation reports, diagrams, transaction
structures, and so on.
Now, let's look at the only tab we have, which includes other sections
containing information. For example, Recent Knowledge Bases displays a list of
recently opened Knowledge Bases with the dates of the latest updates, and
provides links to create new Knowledge Bases or to open existing ones.
Below is an Extensions section with tools developed by Artech or third parties.
They are free to be installed and used, and enable an increased tool power in all
directions.
The section labeled GeneXus Community displays an RSS feed of Community
news, with "More..." links to read the complete stories.
The Address cell allows you to search the Web or your file system without
leaving the IDE.

17

New Project and New Knowledge Base


The first task in developing an application with GeneXus is to create the
Knowledge Base.
At their following meeting at the coffee shop, Mary - still with a concerned
look on her face asked Diego:
"You said that GeneXus enables the automated creation of databases and
programs, but how does it know in which environment and language is should
build the programs? For example, if you had to develop an application in Java and
another application, or the same one, in (.Net)..."
"Lets see... When you create the Knowledge Base we usually call it KB
for short you can set the project to be generated in Java. As we said, the KB is
platform-independent: if you generate the application in Java, you can later reuse
this knowledge to generate it in .Net. You don't have to describe the objects from
reality again, and you only have to associate this knowledge with another
environment. When you associate an environment, you'll find a place to set
everything related to it. For example, in Java, youll have to set the location of the
classes in the webapp, something that makes no sense in .Net. This means that
depending on the selected environment, the program displays the properties
needed to set it. Thats how GeneXus can make your application come true and
implement it as you asked."
Coincidently, as Diego and Mary exchanged words and looks at the coffee
shop, Julia followed the same steps that you can see below.
1. On the File menu, click New, and then click Knowledge Base (or click the
New Knowledge Base link in the Start Page). The following dialog box will
be displayed.

TravelAgency

18

From here, the project is associated with an implementation


environment. Leave "C# Environment," which is the default option. Also note
that English is associated as the default language of the application. All
messages, buttons, etc. will be then in English. But you will be able to later
generate the same application in another language, in both static and dynamic
form (in running time, the user selects the language to be used in the
application), at a minimum cost.
It should also be noted that the KB will be stored in a database whose default
name will be GX_KB_name in the same installation of your local SQLServer.
If you do not have one you may use one from the net. By pressing the
[Advanced] button you can change the values.
2. Click [Create]. GeneXus will create an empty Knowledge Base. The screen
displayed should be similar to the one below.

As you will see, part of the content has changed. There's a tree in the Folder
View panel; the parent node is the Knowledge Base (with the name that you
gave it) and the children are the elements that make it up:
Domains, Tables, Customization, Documentation, Objects, etc.
A new section called Knowledge Navigator has been added to the Start Page.
It has shortcuts to the most common tasks that you most
commonly do after creating or opening a Knowledge Base.
This Knowledge Base will also be used by the rest of the team. Julia is now
ready to start documenting the project.

19

Documenting from the Inside


Documents, notes and task lists are just examples of the documentation
implied in any software development process. Documentation, when it's up-todate and easily accessible, is an important part in every application.
And thats why GeneXus' documentation features are built into the KB.
Documents, files, diagrams, and objects can all be linked, and easily accessible to
every team member, so we say that it's active, integrated documentation that
constitutes an actual wiki.

Files
The department managers had emailed Julia several documents describing
their system requirements, priorities and descriptions of their areas, some process
flows, etc.
Because these documents were created by the end users, she decided to add
them, unchanged, to the Knowledge Base, for future reference. The actual words
of users were important to consider here.
So, she expanded the Documentation tree node and double-clicked Files. In
the new Files tab that was displayed in the main window, she clicked Add New
File. A window was displayed to search her file system and choose each file to be
added to the KB. Below is the resulting Files tab.

Images
She had also received the company's logo, so she accessed the Customization
node of the Folder View tree, double-clicked on the Images tab and imported the
20

Logo.bmp file, which she saved in the KB. Later, it would be used as a header for
the application's pages. In the same email, she received dozens of image files of
tourist attractions that later would be stored in the database. She temporarily saved
them here as well, to have them centralized in the KB.

The Main Document


Now, Julia gets ready to write the main page of the KB's wiki. Note that below
the Documentation node is a Main Document object. Every development team has
a different approach to documentation. At ACME, this main page is used to
describe an overview of the system being developed, and to access documentation
elements.
They could as well create the project's Master Plan here instead of inserting it
as a file. But you and your development team are free to use this page as you
consider most convenient.
Julia opens Main Document and a new tab called Document: Main is displayed
in the main window. Since she wants to start writing, she clicks the Edit selector
in the lower menu bar and enters the text shown below with a format. Next, she
clicks Preview and obtains a normalized view of the text. Finally, she saves the
changes (Preview changes to Browse).

Note she formatted the text through the formatting toolbar.

Julia changed the font type and size, and set the topic title in bold.

21

In addition, she needed to add links to the documents she has received and just
saved in the KB, which is crucial for an integrated documentation. To do so, she
dragged the Table item from the toolbox1 to the page. After inserting the table, she
wrote the following en each row.

She wanted a preview so she clicked the Preview selector. Satisfied with her
work, she saved it and the following window was displayed.

Note that due to the symbols she used in the table's second column, the
documents are now underlined: they are links to the stored files.
As a result, the documentation is very dynamic and actively integrated to the
project through the KB.
The GeneXus documentation editor uses two opening square brackets ([[) and
two closing brackets (]]) in the text to create links.
If you're following this example, you may have noticed that right after typing
the second opening bracket, the editor prompted a list of valid objects to choose
from, as shown in the figure below.

The GeneXus IDE provides dockable function panels that stick to any side of the window. Also, they
can be automatically hidden when the focus shifts so that they don't take up space in the main window. To
activate them, open the View menu and choose Other Tool Windows.

22

Julia selected File, and after typing a period (.) the list of available files was
displayed (she could also have dragged the File object from the toolbox, obtaining
the same result as by writing "[[File.").

Next, she selected each desired file and pressed <Enter>. The text was ended
with two closing square brackets.

Creating the First Transaction: Attraction


Back at the coffee shop, while talking to Mary, Diego thinks that he should
enter the first views obtained by interviewing staff from the Tourist Information
Section at Travel Agency & Co. That department in the company is responsible
for finding information to be added and for removing the necessary destinations
and itineraries offered to customers. He thinks that, as soon as he gets back to
work, he should create the Attraction transaction, when Mary suddenly interrupts
his thoughts:
"You know, Diego, I don't understand how you can accurately describe users'
views to avoid ambiguities and to automatically infer everything."
"Remember the new project we're working on? Well, I've been meeting with
users who handle data on tourist attractions in every country and city, in order to
offer them to customers. They use the attraction's name, such as "Centenario
Stadium," "Roman Coliseum" or "Disney World," and the name of the country
and city where the attraction is located, with images of each attraction. They also
told me that attractions are grouped in categories. For example, the Centenario
Stadium belongs to a Great Monuments category, and Disney World to
Entertainment. These are their views on the data."

23

"I see... And how can you objectively describe those views?"
"With attributes... and with Transaction type objects. Let me explain .
Attributes are the reference framework for other descriptions. It's not exactly the
same as a relational model attribute. Here, attributes are the basic semantic
element. Precise, unique semantics are assigned to their names, and that's why
attributes are so important in GeneXus."
Diego scribbled a few names on a paper napkin: AttractionName,
CountryName, CityName, AttractionImage, AttractionCategoryDescription, and
continued his explanation:
"These attribute names have clear semantic content that anyone can understand
without the need for any context at all. They are not just 'Name' or 'Description.'
Theres a strong relationship between an attributes name and its meaning. That
name, in turn, is a sequence of characters, something syntactic, unique, with which
any program can work without ambiguity. If I write or speak of
AttractionCategoryDescription anywhere, we both know it's a description of the
attraction category. And GeneXus knows this too, because of the syntax."
"So," she cut in, "you can't use the same attribute name to refer to other data,
because that would cause confusion and ambiguity."
"Exactly. An attribute must have the same name everywhere it's used, and there
won't be two different attributes with different meanings sharing the same
name. That's the basic concept. But there's one exception, though. Anyway, I don't
want to get you all confused at this point. These views described by users are used
to handle data (add, edit, delete, view it) and are represented in GeneXus through
the Transaction object type. Every transaction has a set of elements: structure,
rules, formulas, display elements. In other words, in one object we're killing
several birds with one stone: when you set the information that will be used,
you're also designing the screen that the end user will work with, and you're also
defining the necessary data behavior as it is entered, among other things."
Diego grabbed the same napkin and added the following:
AttractionId*
AttractionName
AttractionCategoryId
AttractionCategoryDescription
AttractionImage
CountryId
CountryName

24

CityId
CityName

Then he said: "Data is displayed according to a structure that must be


accurately represented. This would be the structure of the Attraction transaction.
The asterisk next to AttractionId stands for uniqueness: there's only one
AttractionId. That is, it's an identifier that makes an attraction unique. All the
information has to be identifiable, so an attraction must be identified through one
or more attributes."
"But wait Diego, I have some questions here!... Are you talking about the
concept of primary key of a table in a relational model? Will the attributes you
listed be columns in a physical table that will store this information? In the end,
aren't you designing a table with this transaction?"
"Well, indirectly I am. But also no, because I'm not concerned about
designing a physical table of the relational model. I've only specified the
attributes that the end user will interact with to enter attractions into the system.
I've specified a user view, not a table. Heres where the reverse engineering and
the Relational Model inferred by GeneXus come into the picture. If this were the
only transaction in the KB then GeneXus would infer a physical table
containing exactly every listed attribute. But things are not quite that way when
other transactions share some of the attributes mentioned. Those cases would call
for a "normalization, but I don't want to rush things now, Ill come back to that
later, ok?"
"I think I'm getting your point. But I still wonder why in the transaction
structure you added attributes without saying that they were mentioned by the
users. All the ones ending in Id And also, why didn't you use the attraction's
name as identifier?"
"And what if the same attraction name is used to describe attractions in
different countries and cities, like Disney World in Paris, or in Miami, or Las
Vegas, or Disney World in Orlando. In these cases we need an attribute providing
uniqueness to the set of data elements that make up an attraction. Every
transaction structure should have one or more attributes to identify each instance.
In this transaction, it will match the inferred table's primary key, but that's not
always the case. Later, you'll see it in a two-level transaction; but forget about that
for the moment. Now, we can tell GeneXus that AttractionId will be a numeric
attribute and set it as Autonumber."

25

"And what about the AttractionCategoryId, CountryId, and CityId attributes?


Are they identifiers too?"
"Yep, they'll be identifiers in other transactions. Countries, cities, and attraction
categories belong to entities that are independent from tourist attractions. For
example, we haven't discussed this with the customer yet, but flights will also
have arrival and departure cities. Obviously, we'll have to create a transaction to
represent and enter data about countries and cities, as well as existing attraction
categories. As it happens, these identifiers you mentioned will identify each one of
their details (instances)."
"Let me get this right: once you define the other transactions, GeneXus will
infer tables to store their data, and will know that the attributes you added to the
Attraction transaction structure (AttractionCategoryId, CountryId and CityId) will
be turned into foreign keys in the associated relational table."
"Bright as always Mary!" exclaimed Diego with an admiring look.
"But
then,
why
are
CountryName,
CityName,
and
AttractionCategoryDescription in that structure too? In a normalized relational
model, they could never be in that table."
"In fact, they won't be in it. That's why I mentioned that a transaction structure
doesn't exactly match that of the associated physical table. I'll come to that later
on, in more detail. Next time, I'll bring my notebook along. There will be a next
time, right?" he asked a bit shyly, "That way I could show you..."
The following day at work, Diego created the transaction using the GeneXus
IDE. These were the steps he followed:
He first clicked the New Object link in the Start Page and a dialog box for
creating objects in the KB was displayed. He then clicked Transaction in the
Select a Type dialog box containing the GeneXus objects available, and typed
Attraction in the Name field. Following is the screen displayed.

26

Lastly he clicked [Create] and the transaction was opened.


Note that in the following figure a new tab with the transaction name has been
added to the main window. What's being edited? The transaction's structure.

Objects opened in the IDE's main window are displayed as tabs. Only the active
one is displayed in the middle of the screen. The opened object can have several
elements or sections, only one of which will be active each time. At the bottom of
the window there is a bar to select other sections of the active object.

The structure edit window features a set of columns to create attributes, name
them, and set their data types and descriptions.

27

Selectors

In GeneXus, the structure Diego drew on a paper napkin is represented as shown


above. He named the attributes according to the GIK (GeneXus Incremental
Knowledge) naming convention, a standard created by Artech and adopted by the
Community. Its purpose is to give each attribute a unique name that clearly
conveys its concept, or semantic meaning.
As you may have noticed, in the Type column you can give each attribute a
GeneXus-supported data type.

The Blob data type allows a wide range of data (videos, worksheets, all kinds
of documents, audio files, digital images, etc.) to be stored in the database. The
purpose of the AttractionImage attribute is to store an image of the attraction in
.bmp, .jpg, or any other format.
In the Description column, you can enter an extended description of the
attribute. For the moment, we'll leave the suggestions provided by GeneXus based
on the attribute name.
To add more attributes, press <Enter> after completing a definition and repeat
the process.

28

Key Attributes: In his drawing on a napkin, Diego marked the key attribute with
an asterisk. In GeneXus, key attributes are marked with a key icon.
As Diego assigned the data type for the AttractionName attribute in the Type
column, he thought it convenient to create a Name domain for all attributes that
named "something", and an ID one for all those that were numerical identifiers.
You are probably used to working with Domains. If not, go on to the next
paragraph to have an insight on the topic.
Domains?
It is common for applications to have attributes sharing definitions of the data
and size types, and certain other characteristics. For instance, in the Attraction
transaction there are several attributes that are ID (AttractionId,
AttractionCategoryId, CityId, and CountryId). Diego created a domain called Id,
with all the characteristics of identifiers, which he will apply to all attributes
whose function is to represent a non-existent value that is necessary to achieve
uniqueness.

Each domain is a set of unique features that may be shared by several


attributes. This allows for consistency and easy maintenance, since changing
a domain feature will transmit the change to all the attributes based on that
domain.

Defining Domains
Diego double-clicked the Domains node in the Folder View tree, and the tab
for displaying and editing domains was opened in the main window. There, he
entered the Id and Name domains. The process is similar to that of creating
transaction attributes.

Some domains are automatically created by GeneXus together with the KB.
After Diego defined the first domains, he returned to the transaction and as he
substituted domains he realized that he still needed to define a Description domain
29

for AttractionCategoryDescription. Instead of returning to the Domains window


we went to the Type column of the attribute and wrote
Description=Character(20)2. As he left that field the domain was automatically
created. Upon saving, he had the following:

Note that the asterisk next to the transaction name in the tab is no longer there
(the asterisk indicates that changes made have not been saved yet) and that the
Structure selector changed colors.
Descriptor Attribute: What does the magnifying glass icon in front of the
AttractionName attribute mean? It indicates, in the case of having to keep only one
attribute that best described the entity (with more semantic meaning), this would
be the one. This information will be used by automation tools, so we won't deal
with it right now.

The ATTRACTION Table


By default, GeneXus names the tables it defines after the transactions they are
based on.3 At any time, you can view the table's design (structure, indexes, etc.) by
opening the Tables node of the tree in the Folder View panel and double-clicking
on the table's name. For ATTRACTION it will be:

2
3

GeneXus generally offers several ways to do this in a simple way.


From now on, table names will be written in uppercase to tell them apart from transaction names.

30

Given the transaction structure, GeneXus will also design a form for it. This
will be the screen that end users will use to enter attractions when the transaction
is turned into an executable program. It can be seen by clicking the WebForm 4
selector in the access bar.

This form can be customized by moving controls around, by adding, changing,


or deleting them, or by changing their appearance, for example.

With GeneXus X you can exclusively generate Web 2.0 applications. To generate a Win application
you can resort to GeneXus X Evolution 1, where the transaction will also include a WinForm.

31

Satisfied with his work, Diego remembered that he hadn't documented the
transaction. As a rule, ACMEs team members create documentation as they move
forward, especially regarding entities such as the Attraction transaction.
So, he opened the Main Document, inserted a new table called Objects, and in
the first row he added a link to the newly created transaction (just like Julia did a
few pages back when she added links to the documents) with a brief description.

We can see that Attraction is a link. What will happen when Diego clicks it? A
new documentation tab will be opened for the transaction, where he will be able to
edit or even open the transaction.

Suppose that you need to open the transaction to view its structure before
documenting it. You can do so by clicking the Open Transaction: Attraction link.
Then, to open the documentation edit window you can click the Documentation

32

selector. As you can see, dear reader, in GeneXus it's also true that many roads
lead to Rome.

Creating the Second Transaction: Country


Next, Diego created the transaction that would contain data on countries and
cities. Its structure was drawn on the paper napkin that he had kept in his pocket
since his last meeting with Mary:
CountryId*
CountryName
CountryFullName
CountryWorldRegion
CountryDetails
CountryFlag
(CityId*
CityName
CityInformation)

Since he had already opened Main Document, he started from there. He added a
new link in the table, this time to the Country transaction. But he hadn't created it
yet! Note that the link displayed has a question mark (?) next to it.

33

Upon clicking on the ?, Diego will automatically create the transaction, which
will appear opened in the structure, ready for him to enter attributes. The link will
now be defined in Main Document. (Once again: remember that about the roads to
Rome?)

Country: A Two-Level Transaction


It is a well known fact that countries have cities, so reality leads to determine
that there are n cities per country. GeneXus can easily represent this reality with
two-level transactions.
That's why the Country transaction has two levels. The first level, also known
as prolog or just header, is implicit so it does not need to be identified. In this case,
the header's attributes imply that there's only one instance for each country.
But because there are several cities for one country, the method used to
represent it (on paper: a set of brackets proceeded by a name for the level)
determines a set of attributes that are repeated in the header: it is known as "body"
or second level.
Note that both levels (header and body) have their own identifiers: the
CountryId attribute is the first level identifier, and CityId is the second level
identifier. This means that for any given country (CountryId), a city (CityId) can't
be used more than once.
Based on this structure, GeneXus creates two tables: COUNTRY and
COUNTRYCITY. The primary key of the first table is CountryId, and the primary
key of the second table is made up by CountryId and CityId.

34

The following figure shows the structure that Diego entered.5

Because CountryId and CityId already exist in the KB (they were created when
the Attraction transaction was saved), when typing the first characters of each,
GeneXus will open a list with the KBs attributes that show the same start, from
where the corresponding one can be selected. This saves time of further typing.
The same goes for CityId and CityName.

To add a second level to a transaction, click the preceding attribute and press
<Ctrl+L> (in this case, click the CountryFlag attribute). Continue with the rest
of the attributes as usual. You can also do this by right-clicking the attribute and
displaying a context menu to add a new level, move the attribute, etc.

Database Normalization
When the Country transaction was created there were certain changes of
significance. More precisely, the contents of the ATTRACTION table have
changed because GeneXus has normalized it according to the new functional
dependencies added. Following are the new table structures.
Remember that functional dependence XY is a restriction between two
sets of attributes of the database that determines that: if for 2 records the X
values match, then the Y values must also match. This means that the values
of Y attributes in any record depend on the X attributes or are defined by
them.

Note that new domains have appeared. We assume that Diego created them either before or as he
entered those attributes. For example, when entering CountryFullName, in the Type column he could
have entered: LongName = Character(50) with the same result. In the event that Diego had already
defined a Details domain as VarChar(500,200), it's worth noting that when he enters the CountryDetails
attribute, GeneXus will infer the Details domain as its data type (because it's in the last part of its name).

35

Can you spot the differences? By creating the Country transaction and setting
the CountryId and CityId attributes as identifiers of their levels you're defining
that:
1. Every country will be (uniquely) identified by a CountryId value; this value
will be associated with (determine) only one CountryName, CountryFullName,
etc. (these functional dependencies are established). In a normalized Relational
Model, this results in a physical table with the CountryId primary key to store
this data while preserving uniqueness.
2. Every city will be assigned to a country (CountryId) through the CityId value.
Therefore, the (CountryId, CityId) pair will determine a CityName and
CityInformation. Thus, there must be a physical table with the {CountryId,
CityId} primary key to store data about each city.6
So, what does GeneXus do with attributes having the same name in different
transactions?
Remember the two most important statements of the GeneXus philosophy:
Identical concepts must have identical attribute names, and
Different concepts must not have the same attribute names.

Note that GeneXus names the table by concatenating the transaction name to the level name:
COUNTRYCITY.

36

Considering the above, when attributes of the same name are found in different
transactions, it means that they are exactly the same! So, what can GeneXus do to
maintain a normalized inferred database? Transform the CountryId and CityId
attributes in the ATTRACTION table to foreign keys and remove the
CountryName and CityName attributes from that table (they are then inferable
through the previous ones. If they remained there then there would be redundant
information).

Stored Attributes and Inferred Attributes


Here comes the question that Mary asked Diego about the CountryName and
CityName attributes referenced in the Attraction transaction structure. Since they
wont be included in the associated physical table... why did Diego add them to
Attraction?
If you look at the transaction form a few pages back, youll find those
attributes. Why?
That's because the transaction will be turned into a program that end users will
access through their browsers. In a screen designed as the WebForm Editor, users
will be able to add attractions (new records in the underlying ATTRACTION
table).
When end users type a country identifier in the CountryId field and a city
identifier in CityId, they should be able to view the country's name
(CountryName) and the city's name (CityName). This means that CountryName
and CityName are invoked, at execution time, from the COUNTRY and
COUNTRYCITY tables through the combined {CountryId, CityId} foreign key.
In order to be added to the form, attributes accessed through foreign keys must be
in the structure, inferred.
What would happen if the user entered nonexistent values for CountryId,
CityId? What if, through the Country transaction, the user tried to delete a city
with attractions? If we were allowed to do that, we'd be breaking one of the most
important data consistency rules of relational models: referential integrity. In fact,
GeneXus will automatically add in transactions the code necessary for these
controls.

Referential Integrity
Diego told Julia that he had defined the first two transactions. In order to
confirm that the model accurately reflected reality, she drew a Bachman Diagram
(a diagram of relations between tables) of the tables inferred by GeneXus based on
the transactions.

37

To do so, she expanded the Tables node in Folder View and then, from any
table she right clicked to open the context menu and selected New Object,
following which, in the displayed Create New Object window, she selected the
Diagrams object and clicked [Create]. Next, she selected all three tables at once
and dragged them to the blank page to obtain the following result:

In this diagram, the single arrow head indicates that theres one instance of the
pointed table for each instance of the first table; that is to say, for each city theres
only one country, and for each tourist attraction theres only one city. Likewise,
the double arrow head indicates several instances of the pointed table for each
instance of the first table; that is to say, for each country there are many related
cities, and for each city there are many attractions.
This allows determining the relationships between them. For example, the
relationship between COUNTRY and COUNTRYCITY is 1 to n (one to many);
the opposite is n to 1 (many to one). COUNTRYCITY and ATTRACTION also
have a 1 to n relationship.
When adding or editing a record in the ATTRACTION table, the
COUNTRYCITY table must have a related record to ensure referential integrity.
When a record is deleted from the COUNTRYCITY table, there mustn't be any
related records in the ATTRACTION table. GeneXus automatically solves this by
adding this logic to the Attraction and Country transactions in a way thats
transparent for developers. Similar considerations can be made regarding controls
performed on the related COUNTRY and COUNTRYCITY tables.

Base Table and Extended Table


While Julia confirmed that everything was correct, Diego remembered
passages of his last conversation with Mary at the coffee shop:

38

"Listen, Mary, for practical reasons, the table where you're positioned at a
certain time, the one that you're focusing on when trying to do something to its
records, in any context, is called base table. That's why we say that the Attraction
transaction's base table has the same name: every time you work with the
transaction, you'll add, change or delete a record of that table. Then, you'll move to
another one, and another one, and another one. Besides, when working with one
base table record, you can access data that's directly related to it and stored in
other tables."
Following n to 1 relationships, from the record of the base table where we're
positioned, to the record containing the information we want. It's nothing new."
"That's true, only the terminology is new. The extended table of a given base
table will be the set of tables reached from the base table through n to 1
relationships."
"Let's see if I'm getting this right. If data didn't have to be scattered in several
tables to avoid redundancies, you'd have it all in one physical table. For
attractions, you'd have one big table with all ATTRACTION attributes, plus the
COUNTRYCITY and COUNTRY attributes. You can't do that because of the
potential inconsistencies created by redundant data, but anyway, you name the
table that you would" have. And that's the idea of an extended table: it's a table
that you imagine, even though it doesn't exist physically."
"Absolutely true. You'll see that in GeneXus we use this concept extensively,
and that's why it has a name."
While Diego continued reminiscing, Julia confirmed that data access between
tables was ensured.

By looking at a Bachman Diagram you can easily determine the extended table
of each (base) table. All the tables that can be reached from the base table by
following single head arrows (n-1 relationships) will be part of its extended table.
The extended table is a concept and is not actually materialized, but it allows us
to refer to information univocally related to the record that we're using.

Creating the First Prototypes


In order to let Mike play his role as project tester, Diego pressed <F5> to start
prototyping.

In GeneXus, there's no difference between prototyping and implementing a


system. A prototype is no other than the application generated in a certain
platform: same as the final application! The only difference between them is how
they are used.

39

Remember that the environment had already been selected when the KB was
created. Therefore, several properties were already set; 7 for example SQL Server,
the default DBMS. But something is missing to implement the system. An
assistant (wizard) will ask Diego for the DBMS server and database details only
once. The DBMS is Microsoft SQL Server 2005 Express, installed in the
DevelopeSrv server in the net. Diego will name the database as
TravelAgencyTest:

If the database is still to be created, it can be done by pressing [Edit


connection] followed by the Create database link. If this is left for later on, then
GeneXus will do it automatically a few steps ahead.
GeneXus will then go on to generate and execute the Developer Menu, 8 so that
developers can immediately test the applications. Once the environment is fully
set, every time <F5> is pressed GeneXus will carry out all the steps pending and
necessary to execute the application. Diego expected to see what's shown in the
following figure: the first Impact Analysis of this Knowledge Base.

To change one of them, just select the Preferences panel in the KnowledgeBase Navigator and find the
preference to be set; for example, the associated DBMS, the implementation language, etc. Then, access
its properties by pressing <F4> (in the window that is opened).
8
A simple prototyping menu created by GeneXus (it's an xml file containing links to the various
GeneXus objects created, in order to invoke them quickly and easily as we'll explain shortly).

40

This Impact Analysis Report (IAR) told him that GeneXus would create
the tables shown on the left. Their structures and other details such as indexes,
etc.,9 are displayed on the right.
What's an Impact Analysis Report? GeneXus uses the Knowledge Base to
design the database. The existing objects can be changed at any time, and new
objects may be added to modify the KB. The IAR is obtained from an analysis
performed by GeneXus of the impact of new definitions or changes to the KB on
the associated physical database. Through this analysis, the developer knows
about the structural changes that GeneXus will make on the database to update it
and make it consistent with the KB.
Diego agreed with the IAR and clicked [Create] to reorganize the database.10
Since the database didn't exist yet, it would be created in this first step. Later on, it
will be reorganized after being changed and restructured. When are programs
generated? Right now, ready for testing! Barely a minute went by since Diego
pressed <F5> and entered the platform details that were missing (name of BD and
server) until a browser window was displayed with the ready-to-run Developer
Menu. He carefully analyzed some reports previously displayed by GeneXus to
make sure that he was going in the right direction.... But don't rush, dear reader,
because we'll come back to this later and Mike is anxious to step in.

Mike 007... With a License to Kill


It was his turn. He had to destroy them; the transactions, of course.

Below are the SQL sentences that will be used to reorganize (in this case, create) that table.
The term reorganize means to make physical changes.

10

41

Looking steadily at the Developer Menu displayed in the browser containing


links to the transactions, Mike clasped his hands together and cracked his
knuckles. Then he paused. Here we go, he said to himself.

The idea was to start the testing immediately by entering data into the
database that GeneXus had just created and check the transactions' behavior.
He clicked Country and the screen displayed was similar to the following
figure.

42

This is the Country transaction at execution time.


Soon, he noticed that the CountryId attribute should be autonumbered. This
means that the user shouldn't have to worry about assigning it a specific value
because CountryId doesn't represent an object from reality. It's just a number that
makes new records unique.
Likewise, when he found CountryWorldRegion, a one-digit attribute, he didn't
know which numeric value belonged to each world region (how could they
indicate whether a country is in Africa, North America, Europe, etc.?). We have to
show the end user the names of regions and continents to choose from! he thought.
So, he decided to start a conversation with Diego to discuss the issue; so that
they could all agree with his suggestion. He returned to the KB, where he selected
Country and accessed the documentation section.

Making Conversation
Upon opening the documentation, Talk is one of the selectors provided. It
allows us to create a space for dialogs with other users about the object at hand.

Note that the title at the top indicates a Talk document for the transaction. It
ends with a question mark, which means that there isn't a Talk page for this object
yet and that it should be created before writing. When Mike saves this space, a
page will be generated with its content.
Upon clicking the question mark, the view switched to edit mode. Next, he
entered the text, saved it and viewed it:

43

Setting an Identifier Attribute as Autonumber


Later that day, Diego read what Mike had written and replied positively in the
Country transaction's Talk area. He accepted Mike's suggestion, and proceeded to
do the changes.
He wanted to automatically number the CountryId attribute, a numeric
identifier, through the Autonumber feature of the DBMSs that support it.
All GeneXus objects have properties that affect both their look and feel.

Every object's or attribute's properties can be edited at any time by pressing


<F4> to display them in a floating window.

So, Diego selected the CountryId attribute and pressed <F4> in the structure of
the Country transaction.

44

First, he changed the Autonumber property to True, and set the properties
shown in the figure above.

An attribute undergoes cosmetic surgery


To complete Mike's following request in the Talk, Diego went to the
transaction's WebForm, selected the CountryWorldRegion attribute control and
pressed <F4> (Diegos properties window is AutoHide so now the Properties
window shifted out). Inside the control properties window, he set the
ControlType property to Combo Box. Next, he selected the Values property to
open the Values Editor window and entered the values for the attribute. That was
all.

45

If, instead of doing this in the CountryWorldRegion control properties in


the form, he had done it in the CountryWorldRegion attribute properties in the
structure, the scalpel would have cut deeper: it would mean that every time this
attribute was added to a form, by default it would be displayed as a Combo Box
with the indication established, and not as an Edit control. When he realized his
mistake, Diego made this definition at the structure level. This is a good example
of how knowledge is inferred in the Knowledge Base and reused.
At that point he admits that whats more convenient rather, is to create a
numbered domain to be used by any attribute that will represent regions in the
world, particularly CountryWorldRegion. So he edits the domains and creates a
new one, WorldRegion, of the Numeric (1.0) type, and in the properties window
(<F4>) he selects the Enum values property and presses the
button to open the
window and enter the values to be taken up by the numbered domain:

46

This way he avoids having to recall, in the application, that value 8


corresponded to South America in the system. So, from there on, when that value
is to be referred he can write WorldRegion.SouthA, certainly much easier to
remember than 8.
So, he edits the properties of the CountryWorldRegion attribute (for example,
by going to that attribute in the Country structure and pressing <F4>) and changes
the data type for it to be now in the WorldRegion domain.
The value of the ControlType property will immediately change to become
Combo box, and its values are that of the numbered one.

47

Reorganizing (reorg)
Diego has changed some properties of two Country transaction attributes. Will
this indirectly trigger any changes in the physical table? Following is the Impact
Analysis Report displayed after Diego pressed <F5>.

48

Yes, GeneXus found that a table needs to be reorganized. Note the word
Autonumber to the right of the CountryId attribute data type. The reorganization
will have to activate this property at the DBMS level. But, what happened with the
other change, the one to CountryWorldRegion? Nothing! It's not a database
change, only the KB was affected: the WorldRegion domain is still of the Numeric
(1.0) type, so the type of the CountryWorldRegion attribute remains unchanged at
the database level. The main change will be a cosmetic one, and indicates that in
all forms where this attribute is shown, it will be displayed as a Combo Box, with
the values of the numbered domain.
This proves that not all changes done to a GeneXus object necessarily cause
the database to be reorganized. We'll give another example when we explain the
transaction's rules.
Diego can have GeneXus do the reported changes ([Reorganize]) or cancel the
reorganization. If he cancels it, the IAR will be redone the next time he presses
<F5>. He chooses to reorganize.
When rereading the Talk to reply that everything has been done, Diego realizes
that Mike suggested autonumbering all transaction Ids by default. (His confusion
was caused by Mike documenting this in the Country transaction Talk, instead of
doing it in the Main Document Talk). To implement this, would he have to change
the attribute properties one by one? No! He remembered that those attributes were
based on the Id domain. So he only had to edit the domain properties and set the
Autonumber property at the domain level, just as it was done for CountryId. All
current and future attributes based on that domain will automatically inherit this
property!
But... Here's a problem! Diego thought. CityId is not a single primary key. To
be set as autonumber, attributes must be a single primary key. CityId is part of
COUNTRYCITY's primary key.11
How can he prevent this attribute from taking the Autonumber True property
from its Id domain?12 Simply by editing the CityId attribute properties (as with
CountryId) and changing the Autonumber property to False. In this way, the
domain's default behavior is changed for this attribute.
The same applies to the AttractionCategoryId attribute which currently
belongs to Attraction and is not a primary key. However, it will soon become a
primary key when Diego creates the new AttractionCategory transaction. For this
reason, Diego decided not to change the Id domain definition for the moment (to
activate the Autonumber). He'll do it later, when he creates the new transaction
(he documented this "To-Do Diego", which was saved in Orphan Documents after
being created by selecting the Document object from the New Object window).
11

To assign consecutive values to this attribute, Diego will have to use the Serial rule. We suggest that
you read about it after you see the following introduction to rules.
12
GeneXus is aware of this restriction. So, even if Diego hadn't spotted the problem, the system would
have acted intelligently: it wouldn't have defined the attribute as autonumber in the database. For
learnings sake we preferred to put Diego to work.

49

Transactions: Not just a pretty face; they also have personality


Diego added to the transactions the behavior described by users regarding data
management.
"An attraction must never be entered into the system if it doesnt have a
name." Thus, he opened the Attraction transaction, clicked the Rules selector and
typed the following rule:
Error('Attraction must have a name')
if AttractionName.IsEmpty();

If users don't complete the AttractionName field, the previous message will be
displayed at execution time, and the control wont let them move on to another
field. Saving the record in the corresponding table won't be allowed, either.
"A country must never be entered into the system without a name and full
name. The country's details can be left blank, but a warning message should be
displayed to the user in case they were overlooked." So, he clicked the Rules
selector in the Country transaction and typed these three rules, in random order:
Error('Country must have a name')
if CountryName.IsEmpty();
Error('Country must be in full')
if CountryFullName.IsEmpty();
Msg('No country details were provided. Do you want to continue?)
if CountryDetails.IsEmpty();

The third rule also triggers a message, but unlike the Error rule, it allows the
user to move on to the next field and save the record.
Many other rules can be used to program the transaction's specific behavior.
Note that they are written in declarative style and, with few exceptions, the order
in which they are added is not relevant. In our case, they will be triggered
depending on the order of the CountryName, CountryFullName and
CountryDetails attributes in the form.
In a two-level transaction, the records of two tables are being handled.
Therefore, when the user enters a new country and its n cities through the Country
transaction form, n+1 records will be added: 1 in the COUNTRY table and n in
the COUNTRYCITY table. They will be added following the same order used to
enter them into the form. A rule may be triggered immediately before or after one
of these saving operations. To this end, rules can be conditioned not only through
if clauses as shown above, but also through trigger events such as BeforeInsert or
AfterInsert.

50

After saving the transaction's n+1 records (1 header and n lines) a Commit is
automatically performed. It can be disabled by the GeneXus analyst through a
transaction property. In addition, rule triggering events capture the moment
immediately before or after the Commit operation. For example, to get a list of the
newly entered country and its cities, you can invoke another type of GeneXus
object: Procedure. You must invoke it after entering the n+1 records, by sending
the newly entered country Id by parameter. To obtain it before the Commit
operation, write the following rule in the rules section:
PrintCountry.call(CountryId) on BeforeComplete;13

If you want it after the Commit operation, use the following rule:
PrintCountry.call( CountryId ) on AfterComplete;

Diego documents the changes already made. Think about the changes made to
the KB since pressing the previous <F5>.

What's hiding behind <F5>?


1. When you press <F5>, GeneXus first makes an impact analysis of the KB
changes on the database. When there's an impact, it will display the Impact
Analysis Report, which can be confirmed to physically reorganize the
database. As we've seen, it can also be cancelled.
Diego knows that the only changes he made since he last pressed <F5> was
add rules to both transactions, that's why he doesn't expect a reorganization the
next time he presses <F5>. However, he knows that the following steps will be
carried out.
2. GeneXus steps into the specification stage, which is an analysis of everything
defined in the elements making up the objects that you have changed, be they
structures, forms, new rules, etc. This task results in a navigation report where
GeneXus shows the logic interpreted for each object that has been changed
since the last <F5>, together with warnings and errors, if any.
In our friends example two objects have changed: Country and Attraction, so
Diego will see the following after pressing <F5>:
13

The Call, a common invocation method in GeneXus, is being used as a rule. Note that the invoked
object's name appears before the call; in this case it is a Procedure, another GeneXus object. Lastly, note
that trigger events are identified in the syntax of a rule:
Rule if condition on Event
Condition is a Boolean condition and Event is a valid trigger event. In the product's documentation you
can read more about other trigger events such as AfterValidate, BeforeInsert, BeforeUpdate,
BeforeDelete, AfterInsert, AfterUpdate, AfterDelete, BeforeComplete, AfterComplete, etc.

51

There weren't any warnings or errors. Note that, upon selecting Country on the
left, it shows the tables where the saving will be done, and the referential integrity
checks that will be performed when deletion of a country or city is tried through
this transaction.
3. After the specification stage comes the generation of the object(s) that
GeneXus deems necessary to completely perform the execution. (If there are
objects that haven't been changed and were generated in a previous <F5>, why
do it again?) The generation entails writing lines of code to implement the
programming of objects in your chosen language for the development
environment (for each transaction of the two that Diego has, a .cs file will be
generated among other things. Dont forget that he chose C# as the
development language). Also, while the developer does not create his own
main object, an xml will be created: the Developer Menu which will contain
links to all programs (objects) generated.

52

4. Lastly, GeneXus compiles the programs and executes (while a main object in
the execution is not created) the Developer Menu in the browser installed in
that computer.
This whole process is fully automated. You'll never have to specify and/or
generate an object explicitly, because GeneXus is intelligent enough to determine
which actions to trigger at each time.
That's how, upon Diegos warning and previously opening the Developer
Menu, Mike executed Country, where he added, updated and deleted a few
records. Finally, he documented the results in the transaction's Documentation,
changing its status to OK.
Note what happened when, accidentally, with country 1, Argentina, being
edited he erased the name and exited the filed Remember that shortly before
Diego had programmed an Error rule with that same message?

He still hadn't tested Attraction (he had found things to change in Country, so
he had decided to put it on hold for a while) when he read in the Talk that Diego
had asked him to delay the test until he created the related transaction that came
next.

53

Creating the AttractionCategory Transaction


Diego
added
the
attribute
pair
AttractionCategoryId
and
AttractionCategoryDescription to the Attraction transaction, even though he knew
that later he'd create an AttractionCategory transaction to contain them.

This transaction categorizes the attractions of each country's cities:


"Buildings/Structures," "Nightlife," "Relaxation," "Adventure," "Gastronomy,"
"Safaris," "Business," etc.
With the Attraction and AttractionCategory transaction structures we're
implying that an attraction belongs to only one category, while a category can
contain n attractions.
The following Diagram shows the new existing relation between the tables
involved up to now in the project.

The next time <F5> is pressed, GeneXus will have to reorganize the database
by creating the new ATTRACTIONCATEGORY table and removing the
AttractionCategoryDescription attribute from the ATTRACTION table. From
now on, this attribute will be inferred from the new foreign key
AttractionCategoryId.
Before pressing <F5>, Diego remembered to set the Id domain as
Autonumber (he had left a note to do it when he created the AttractionCategory
transaction.)
Finally, he pressed <F5> and read the corresponding Impact Analysis Reports.

54

Note how changes made in Attraction are informed. And for


AttractionCategory it informs that the table is new and must be created. It also
includes a warning14:

After clicking [Reorganize] Diego obtained a new database and the newly
generated programs. He closed the browser because Mike would be in charge of
testing, and documented the new transaction and Autonumber settings.
Mike read Diego's notes, prototyped all transactions and again pressed <F5>...
14

What if Mike had previously tested the Attraction transaction and had entered records prior to this
reorganization? Suppose he entered an attraction with Category 1 Id and a description Nightlife
What would happen then in the reorganization upon creating the ATTRACTIONCATEGORY table and
AttractionCategoryId
becoming
a
foreign
key
in
ATTRACTION
and
after
AttractionCategoryDescription being inferred? What will happen to the pre-existing record in
ATTRACTION? For a consistent database, a record will have to be created in
ATTRACTIONCATEGORY, with Id 1 and described as Nightlife. The reorganization program will
do this on its own. What would happen if there were two or more attractions with the same category Id
and different descriptions? This is what the warning informs. Find out what it is.

55

To free end users from memorizing foreign key codes, GeneXus automatically
creates objects called Prompts, which are invoked through the icon displayed
next to all foreign key fields at execution time. They are selection lists that show
the entire data of the referenced table for the user to choose from.

While testing the Attraction transaction, Mike tried to enter the attraction
category of the Eiffel Tower but couldn't remember the code of the corresponding
Buildings/Structures attraction category. So, he pressed the
icon next to the
category Id field. A category selection list, automatically created by GeneXus,
was displayed as shown in the following figure.

Mike will select the first option on the list, Buildings/Structures, and the
control will return to the Attraction transaction. The AttractionCategoryId field
will display the value 1; the focus will be there and the user will be able to move
on to the next field (in this case, country Id, for which the process can be
repeated).

56

To confirm that the referential integrity checks were being made, he entered a
nonexistent category value in AttractionCategoryId. At execution time, he
obtained an error message about it.15

GeneXus can "disguise" an attribute for it to appear as another attribute at


execution time, so that end users don't have to open these selection lists every time
they enter foreign key values. Mike suggested this and Diego implemented it by
changing two properties of the AttractionCategoryId attribute. As a result, to enter
the Buildings/Structures category, now Mike only needs to remember and type the
first letters, and they will be autocompleted.

The attribute where the end user will enter the description is actually the
AttractionCategoryId foreign key disguised" as AttractionCategoryDescription.
This way, though the end user enters descriptions, the corresponding Id is
retrieved from the table and stored in a transparent way.
They still had to improve the project's usability and appearance, so they wrote
about the need to use other GeneXus tools, such as GXpatterns. Maybe they
could all meet and discuss whether to put a part of the application in production in
15

Seconds later, he would try to delete a category with related attractions from the AttractionCategory
transaction. He expected it to fail in order to ensure referential integrity. Dear reader, you can also try this
for yourself.

57

the agency's tourism section. This would allow them to test it, enter countries and
cities, and send any feedback obtained.

Prototyping is a great resource which, if used properly, will avoid an overly


significant dependency on the final test, or even on deployment (D-Day, when
everything happens and Murphy's Law especially applies).
Breogn Gonda & Nicols Jodal

Given GeneXus' features, anything can be tested at any time. And particularly,
it is possible to prototype each object at the time most convenient for it. This is a
crucial capability that stems directly from the GeneXus theory, more specifically
from the automatic propagation of changes.

58

Chapter 3

Machine-made, Hand-finished
Immediate Plans
The Travel Agency & Co. project is well under way, enough to move several
parts to pre-production. Now the time has come for tests to be done by end users
as the system is further developed.

Problem: A Pretty Plain Application


Julia meets with the end users to get their first impressions and address
possible sidetracks. They like the controls and data input method when entering
data through the transactions, but would prefer queries with more sophisticated
views and increased functionality. For example, they want to work with countries
in a more visual and user-friendly way, and the possibility to view all existing
countries on a grid and select one to update or delete it, or even view the country's
full details, including cities and any other related data.

Solution: An Appealing Application, Only 3 Clicks Away


Patterns: here we come! Julia said to herself without hesitation. With the
Country transaction in Edit view, three clicks and one <F5>, she asked the end
users, "Is this what you have in mind?"
The end users view a new link in the Developer Menu: Work With Country,
which, when clicked, opens a new object in the browser: WWCountry, which not
only displays a grid with the systems existing countries - sorted by name, their
most meaningful attribute16 -, but also allows filtering by name in that same grid
(as the end user enters data in the filter variable, it is automatically filtered in the
grid). In addition, it provides automatic paging of the grid17:

16

See Chapter 2, page 27. When entering attributes in a transaction structure, the first attribute of
Character or VarChar type entered is marked as the descriptor. You can change descriptors by rightclicking the new descriptor in the structure and clicking the Toggle Description Attribute option in the
displayed context menu. But, as we'll see soon, Julia will have another option to do it.
17
The default value is 10 records per page (that is, it loads 10 grid lines). We've changed it down to 3 in a
centralized location of the Work With pattern that we'll see further ahead.

59

Grid filter

For browsing grid


pages

In addition, it allows performing the following tasks:


Insert a new country by clicking the
icon displayed in the grid's upper
right corner. This will call the Country transaction in Insert18 mode (to add
a country and its cities) and return.
Update a countrys data by clicking the icon displayed on the grid line
corresponding to that country (it will also call the Country transaction, in
Update mode this time, to update that country and return).
Delete a country from the system (by clicking the
the transaction in Delete mode and return.

icon). It will also call

Display all the information on a certain country (note the link on the
country's name). Clicking it opens ViewCountry, a new object
(automatically created) that will show all the countrys related data (in
tabs):

18

The Transaction object has a predefined variable, &Mode, which identifies its mode at a given time
(Insert, Update, Delete or Display mode) depending on the operation to be performed. If the mode is sent
by parameter and this variable is received, the transaction will know what operation will be performed.

60

Essentially, a real Work With Countries has been created. Users could ask for the
same functionality to work with other entities such as attractions and attraction
categories.

Patterns Anyone?
Overall, you may already know what patterns are about: they are common
knowledge that can be applied to different situations. A GeneXus pattern is very
powerful; not only does it free you from manually creating functionally versatile
objects, it also enables knowledge reuse. In addition, it's an open tool: if you need
it, you can create your own patterns. They greatly enhance productivity and
generate high-quality applications with more uniform interfaces and consistent
logic. Based on knowledge, patterns generate knowledge.
All Julia did was apply the Work With pattern (one of the available ones) to
the Country transaction, obtaining part of an application that implements
everything needed to Work With... the related information, in our case:
countries.
We can think of the Work With pattern (and of many others) as a machine
whose input is a transaction (and the KB), and whose output is a set of new
GeneXus objects (some of them were shown running), plus changes to some KB
properties, plus the modified transaction itself19...

19

More specifically, the transaction must declare that it receives parameters, as now we want to invoke it
from the Work With Countries object (WWCountry).

61

Customization: There's Always a "But"


The end users answer to Julias question was "Yes, thats what we wanted
but...
1. In the grid we only want to view the countrys name and world region (the
other details are not relevant to us).
2. We also want the displayed countries to be sortable not only by name, but also
by world region and by the {world region - country name} pair.
Finally, we want the capability to:
3. ... filter the grid by world region (in addition to doing it by name.)"

To apply the Work With pattern, Julia only opened the


Country transaction, clicked the Work With selector at the
bottom (1st click), selected the Apply this pattern on save
check box (2nd click) as you can see in the following figure,
and saved (3rd click). Then she pressed <F5> (after which the
users could see the application running). Note the new
objects created and displayed in the browsing list:
However, in the figure below you can see that the Work
With selector not only lets you select the check box, but also edits a tree structure
that Julia didnt even look at in the previous steps. Heres where she will have to
work to make the requested changes.

62

Sets up the
WWCountry
web panel:

Sets up the
ViewCountry
web panel:

This figure shows an "instance" of the Work With pattern, the Country
instance, which lets you customize it.20 We can view a hierarchical structure with
nodes and a set of properties whose values determine the appearance and behavior
of what's generated by the pattern for this instance.
Among other things, the Work With pattern will generate two new GeneXus
objects that weve seen running, and that we've included for you over the instance
figure. They are of a type that we haven't discussed yet: Web Panel. Overall, it
lets you make user-friendly, interactive queries to the database.21
In the figure we've indicated which nodes of the pattern instance allow setting
up which web panel's features. The end users have asked Julia to change the first
web panel. For the moment, they haven't said anything about the second web
panel (but they may do so...).
Look at the first thing displayed under the "Level (Country)" node. Remember
that CountryName was the transaction's descriptor attribute
(the one with more
semantic meaning): you can also update it from here. Does the descriptor attribute
have any effects on what's generated by the pattern? Yes, many. For example, it
20

We still haven't defined "instance". It can be thought of as the declaration of how the pattern will be
applied to the particular case of this object.
21
On one hand we have a web panel that, among other things, lets us list countries filtered by name. And
on the other hand, we have another web panel that shows all the information on a given country and its
cities (these in a grid within a tab).

63

defines which attribute of the WWCountry grid will be linked to the ViewCountry
web panel that is automatically created to display this country's details. But this is
just an example; as we'll see, it is used in several places. Nevertheless, the
descriptor attribute, inherited from the transaction, despite the possibility of being
replaced in the tree which does not imply its replacement in the structure, is just
the descriptor for the pattern.

WWCountry web Panel: Selection (Work With Countries) node


Note that the Selection node has three subnodes: Attributes, Orders and
Filter (besides the actions: Ins, Upd, Del, Dis).
By default, the Attributes subnode shows all the attributes of the Country
transaction's first level, and they are those listed (by chance?) in the grid of the
generated WWCountry (Work With Country)22 web panel.
The users asked Julia to display only CountryName and
CountryWorldRegion, so she simply has to delete from this node, by pressing
<Del>, the rest of the attributes except for CountryId. This attribute cannot be
deleted carelessly. Though not displayed for the end user in the grid, it must be
included (hidden) as we will justify shortly. Therefore, in this case Julia will click
that attribute node and press <F4> to edit its properties, setting the Visible
property to False. The resulting instance is shown below, where you can view the
effects running.

Requirement No. 1 is ready!


22

The WWCountry web panel's description is in the singular: "Work With Country." However, in its
screen it's displayed as "Work With Countries." Hence, to mention it we'll use either the singular or the
plural, depending on what sounds more natural for the context in which it is referenced.

64

The Orders subnode indicates the desired default order to retrieve the data that
will be loaded in the grid. This default order selected is (by chance?) that of
CountryName, the descriptor attribute. The end users asked to be able to choose
between this order and CountryWorldRegion, as well as another one made up of
both.
How can the user decide, at execution time, by which order to sort the
information to be retrieved? Through a combo box showing all options available.
Julia will have to add the new sorting orders requested under the Orders subnode,
and give them names (World Region, Both) that will be the options viewed by the
end user at execution time in the combo box automatically inserted by the pattern.
Following is the resulting instance and the generated web panel (running):

Note this: at execution time, you can also order what you have loaded in the
grid at a certain time, by one column, simply by clicking it. But careful! If you're
working with paging, only the currently loaded page is being ordered here.
Requirement No. 2 is ready! Only No. 3 to go.
The end users also want the ability to filter the countries to be loaded in the
grid by world region. The obvious answer: the instances Filter subnode. Note
what's displayed by default below this node (see page 63). Again, it happens to be
CountryName. Take a moment, dear reader, to figure out the meaning of the
subnodes Attributes and Conditions by looking at the WWCountry web panel
implemented by GeneXus and the instance on see page 63. And now, what if we
show you what Julia did in the instance and the effects it had on the web panel?

65

When the CountryWorldRegion attribute is added under the Attributes


subnode, a variable with the same name, &CountryWorldRegion23, will be
automatically created. It will be placed on the web panel grid and allow the end
user to select a world region, causing the grid to display only the countries in that
region (why is it displayed as a combo box24
?
How does it know that it has to apply this filter? From what Julia wrote under
the Conditions subnode. Note certain details: two filters were defined (country
name and world region). Which one should be applied? Both, unless one of them
must not be applied (look at each filter's "when" clauses. For example, when
&CountryWorldRegion has the value of the corresponding domain equal to None.
In this case, the filter will not be applied).
Requirement No. 3 is ready!
Interestingly, and not by chance, when Julia explained to the users how to
update or delete a country at execution time, the Country transaction was opened,
and the country selected from the grid was edited. To do so, the Work With pattern
had to change the transaction's rules by adding some to the ones we had declared.
What for? To instantiate, edit the country and receive it by parameter. Let's take a
look:

23

You may have noticed that throughout the GeneXus code, variables are identified by an '&' added as a
prefix to the variable name.
24
Remember that the CountryWorldRegion attribute is based on the WorldRegion domain of the type
enumerated. That way, when presented in a form control, it should be displayed as a combo box. This is a
variable based on that attribute, so look how it inherits the same behavior, without setting anything.

66

To declare the parameters received and returned, all GeneXus objects use the
Parm rule.

When you use "Work With Countries" to select a country from the grid to
update it, this transaction will be invoked through the "UPD" mode received in the
&Mode variable. In addition, the corresponding CountryId will be sent (that's why
we had to leave it hidden in the grid). To insert, 'INS' is sent together with the
empty value as second parameter, and so on...

ViewCountry web Panel: View (Country Information) node


Upon clicking the country name at execution
time, the ViewCountry web panel is opened to
display the data on that country (see page 61).
Let's see what data is displayed: the country
name
received
by
parameter
(again,
CountryName, by chance?), and then, in a
General tab, all the attributes of the Country
transaction's first level for that country and two
buttons for calling the transaction, passing that
country by parameter (to update and delete it,
respectively). In a City tab, it displays a grid
with all the country's cities.
Pay close attention to the View (Country
information) node of the Country Work With instance. If, in addition to the
country's name, the user asked to view the country's full name in the fixed part,

67

only the CountryWorldRegion, CountryDetails and CountryFlag attributes would


be displayed in the General tab; and if he also wanted the City tab, the cities' grid,
to display only their names, what changes would he have to do to these nodes?
What if the user didnt want a City tab at all?
In the instance, there will be a "Tab" for each subordinate table (many to 1)25...
but Julia could add other Tabs... with other things... but let's not rush...
In sum: when Julia selects "Apply this
pattern on save" in the Country Work With
selector, GeneXus objects such as those we've
seen running will be generated upon saving.
They can be accessed in the Folder View, below
the transaction. Likewise, every time the
instance is modified, saving will cause the
automatic regeneration of the corresponding
objects.

More?
End users, who seem to be assigned the task of finding the weaknesses of
developers and make their lives miserable, asked Julia not to go back to the
caller, WWCountry after updating a country. Instead, they wanted to view the
full data on the newly updated country (that is, go to "View Country").

Without batting an eyelash, Julia clicked the instance root node and changed
the AfterUpdate property value to "Go to View"...
Note that first it takes a "<default>" value, which has to be indicated
somewhere (the same goes for the others). This value sets the default behavior of
all instances (this one is Country, but we may also want Work With Attractions
and Work With AttractionCategories). If we want most or all of the application's
25

COUNTRY only has COUNTRYCITY in this relationship (many cities for every country) and that's
why there's only one Tab. Note that the name chosen by GeneXus was the description of the Country
transaction's level 2 (the description of the lines, which was City).

68

Work With objects to default to View after updating, we don't need to manually
edit this property in each transaction instance. Instead, we can change the
"<default>" value in one centralized location. Where is this centralized location?
It's under the Preferences group in the Knowledge Base Navigator window:
Patterns node. Note that in the following figure only the Work With and Category
patterns are displayed. But there will be other patterns created by you, by Artech,
and by others...
("Extensibility"... "Integrability"... key pieces in the X ideology).

This figure shows all the default behaviors to be inherited by individual Work
With instances for each transaction. For example, to change the number of records
per page in grids for all Work With grids, (which we had already done without
mentioning it, passing to 3), we have the Grid node.26 Interested readers can
search for more about the general settings that can be configured here. For
example, you can change the overall appearance and names of the pages, as well
as the icons for Insert, Update, Delete operations and much more.
Reflect upon what it means to "work with." What else could the picky end user
ask for? (Readers will have to understand that we are also human beings!). Just
ask Julia, and she'll tell you that, in that same meeting, it occurred to these
special end users that they wanted to:

26

If you look at the Page property of the Grid node in your KB, you'll find that it has the Page.Rows
value. What's a Page? It's a numbered domain, automatically created, with only one value (Rows) and a
default value of 10 that we have changed to 3.

69

A. Export the country data that they were working with, to an Excel
spreadsheet. Can you believe it? In addition, they did NOT want:
B. Countries to be deleted from the Work With Countries. If this weren't
enough, they DID want to:
C. Add another action for countries (besides Insert
and Update ) for
opening a new window with each country and its cities all at once!
AND, in a more appealing visual format. (It sounds a bit vague to us... as it
did to Julia too).
Julia felt sardonically amused: every time the demanding end user asked for a
new requirement, she made a few clicks and there it was! Except for this last
request, where he managed to puzzle her. But not that much, we must recall that
Julia isnt an IT specialist, so back at the office she'd ask Diego for help.

Actions Available from Work With Countries

Here are the actions offered by the Work With


pattern for implementation on the WWCountry
data that it works with. Note that theres an
Export
Export option. Default values, again! Yes,
again. They will be set in the WorkWith object
that we've seen before, where all this is
centralized. In our case, the default values for
Delete and Export were respectively True and
False. To disable the delete action and enable the
export action for a country, Julia only had to
change the above combo boxes, setting them to False and True, respectively.
Requirements A and B ready to go!

70

Now theres only requirement, C, still pending, that is: adding an action that is
not predefined. But the object to be invoked by this action is not created by the
Work With pattern; it should be custom-made for this specific data, so its not like
any usual work with. This is a job for Diego, wholl implement that object in
GeneXus. In the WorkWithCountry Documentation selector, under a "To-Do
Diego" title, Julia writes that this task is pending. It will be implemented by Diego
when he gets down to it.27 Which Documentation selector? Note the tab that is
opened upon double clicking on the WorkWithCountry node of the Folder View
under the Country transaction see page 63 and next.

Can never get enough: "I Want more!"


Back from her meeting with users, Julia received an email from the
users! They wanted the list of countries from Work with to include at least part
of each countrys details, CountryDetails, so they could provide their customers
with brief information on each. They also wanted to view the number of
attractions in each country.
So she needed to add two new columns to the Work With Countries grid
one for the brief description and a second one for the number of attractions. But
she didnt know how to do this, since this information wasn't stored in database
attributes. Instead, it had to be obtained through some kind of data processing. She
was planning to call Diego anyway to ask him how to implement the pending
requirement, C; so she grabbed the phone at once.
Diego created a ShortDetails
domain of the Character(70) type.
Then he opened the Country Work
With Pattern Instance. Through the
Add command he added a variable to the grid.

27

Further ahead you'll see that Diego will easily find Julia's note that is part of all the documents that
seem to be "scattered" among so many KB objects, thanks to the Dynamic Categories that he'll talk about
in Chapter 6.

71

Note that, in the properties dialog, a name and a domain must be assigned to
the variable being inserted (thats what the
indicates). Diego names it
ShortDetails and assigns it the newly created domain with the same name. He only
needs to determine the value to be taken for each line in the grid.
"As you can rightly guess, Julia, when you put the attributes under this node,
nothing else was necessary: GeneXus would run through the COUNTRY table
and, for each record matching the conditions in the specified filters (in our case,
CountryName and CountryWorldRegion), it would load a new line in the Work
with grid, with those attribute values in each column. If users wanted the full
country description, you'd only need to include the CountryDetails attribute, but
what they actually want is to shorten it to 70 characters. So, all we need to do is
specify, in the LoadCode property of the variable weve entered, the value for
each line. This will mean keeping the first 70 characters in the string, 28 that is:
&ShortDetails = Substr(CountryDetails,1,70). Yes! CountryDetails is the
attribute. Its that simple. You can do it on your own now."
"Oh, I see So, for the other requirement -displaying the number of
attractions in each country-"
"Well, in that case, the processing needed to load the variable containing that
information will be a little more complex. Think of this: every time a country is
loaded in a grid line, all the countrys attractions have to be run through for
counting them. And we will have three options: one is to program the code that
allows running through the information29 in the LoadCode, again; another one is
to add an attribute containing that information to the Country transaction, for
instance a CountryTotalAttractions. This way, you only need to add this attribute
to the Attributes instance node and thats it!"
"But, I dont understand... In this case, when entering information on a given
country through the transaction, will the user enter the number of attractions it will
contain? What if it doesnt match the actual number of attractions? Users wont
like that."
"Youre absolutely right Julia! I think they will offer you my job anytime. It
wouldnt make any sense having the user enter a number that results from a
calculation of database values. This attribute, CountryTotalAttractions, will be of a
special kind, called formula in GeneXus. See, I just enter this new attribute in the
Country transaction structure and let GeneXus know I have more information
28

GeneXus offers multiple functions for working with different data types. In particular, there is the
substr function that allows retrieving a substring from a specific string.
29
The For Each command, which we will be considering in Chapter 5 ahead.

72

that I know how it must be calculated, and that it mustn't store it in the database
but calculate it every time its value is requested, as Ive determined."

"Count(AttractionName)? So, that tells GeneXus that you want the number of
associated values30 in AttractionName to be counted for that country, right? Now,
how does GeneXus know that it needs to count the number of attractions for that
country and not for all countries?"
"If you remember that GeneXus knows the relationships between data and the
fact that an attraction belongs to a given country and city, and that each countrycity belongs specifically to one country, it will be enough."
"And how is this solution better, as compared to adding a variable in the
pattern instance and defining how to make the calculation with the For Each
command you mentioned? (Which, mind you, you still havent told me how its
done)"
"Well, youve implemented a general solution here. In other cases, in other
objects, when you retrieve a country and want to know the number of attractions
there, youll only need to name the formula attribute and the calculation will be
triggered without the need for manual programming. Now, you just have to add
this formula attribute to the instance Attributes node. And Voila! We have
solved the two requirements in the email!"
But wait! You said we had three options for this implementation and so far
youve mentioned only two
30

For you as an IT expert: for each country, count the number of associated records in the table where
AttractionName is located; right now it's ATTRACTION.

73

Good, I was hoping youd ask that, replied Diego. In fact, the third option
would have been my choice from the start, but I didnt mention it so we could
have the chance to go over the global formulas issue. What we did would be most
recommendable if we are in for the attractions calculation in numerous instances
and for several locations. But if they were not so many, then the best would be to
directly define the variable as before, in the Attributes node of the Work With
instance
(&CountryTotalAttractions,
for
example),
and
specify
&CountryTotalAttractions = count ( AttractionName ) in the variables
LoadCode property.
But isnt it the same formula we had before? inquired Julia.
Yes, but no. Here you havent defined a formula attribute. You are using the
formula locally, as if it were a function. Because of the context where it is
specified in this case it will be in a grid that runs through the country table the
system will know that it must only count the attractions of the country entered in
each case, said Diego.

GeneXus has various kinds of formulas (for adding, counting, searching,


maximizing, minimizing, averaging, etc). They can be defined globally as
attributes, and also locally as needed. When defined globally, attributes are
virtual, that is: they wont be stored in the database.

And, with an <F5> he showed Julia how the work with countries looked:

GeneXus has various kinds of formulas (for adding, counting, searching,


maximizing, minimizing, averaging, etc). They can be defined globally as
attributes, and also locally as needed. When defined globally, attributes are
virtual, that is: they wont be stored in the database.

74

Quod Pattern Non Dat, GeneXus Praestat 31


In the time it took Julia to pour herself a cup of coffee, say hi to a coworker
and walk back with her cup of steaming coffee, Diego was able to implement the
last requirement (C, which was pending). Since they were not sure if they were
implementing what the users wanted, they emailed them the following screenshot:

"How could you do it so quickly, Diego? Will you show me? Im sure its not
that difficult."
"Of course its not. All I did was create a new object in GeneXus, of the Web
Panel type. Its the one you can see running on the screen. What you want is to
display information on countries and cities (in each country). Forget the countries
for a moment, and suppose you only want to list city information in a grid. All you
need to do is insert a control of this type in the web panel form and specify which
attributes will make up the columns. Simply by doing this, when you press <F5>
youll see all existing cities listed at execution time. From the attributes present,
31

Authors note: The phrase that mentions patterns and GeneXus in this case, ironically refers to the
Latin saying Quod natura non dat, Salmantica non praestat meaning: "What nature does not give,
Salamanca does not provide." In other words, the Spanish University of Salamanca cannot miraculously
make a person intelligent.

75

GeneXus infers which table you want to browse (called a base table). Look, he
created a Cities web panel in a snap, then inserted the grid through the toolbox
offering all the controls that may be inserted in a form, and chose the CityName
attribute, to finally obtain the object form shown in the figure below, in our case,
the attributes we included in the grid (CityName) come from the COUNTRYCITY
table, the one that GeneXus will navigate."

"The grid weve inserted is what is known as a simple, standard Grid, that
allows displaying information from a record in a table (and in its extended table),
and has one information element per column. Note that our grid has only one
column, with one title, corresponding to the CityName attribute. If we had a
second one, it would be placed in another column. But lets leave cities aside for a
while, and suppose you want something quite similar for countries, except that in
this case you want to display each countrys information in a more flexible way
instead of in strict columns, like what you see in the screen we sent to the
customers. Look at the web panel I put together while you went to get your cup of
coffee:"

76

"Now you can see the cities grid along with the CountryFlag and
CountryName attributes, inside a rectangle. This is another type of grid called
Free Style, since the country information to be displayed is not in columns but all
together within your selected design. But because its also a grid, itll display all
possible countries in the country table. Note that among its properties, theres one
called Columns which Ive changed from value '1' to value '3', and thats why you
can see three countries per row in the image we sent to users. Rows '0' means that
no paging is to be done and all existing countries will be displayed. Also note that,
inside the Free Style, we can enter any control, including another grid. By doing
this, we allow GeneXus to find the relationships among tables. Thats why the
system automatically lists cities per country in the grid, without the need for
instructions from us. You can see this for yourself in the navigation report
displayed following the specification after the <F5>. Let's see if you can figure it
out..."

77

The country being


loaded in the grid

"I can sure figure out WHY you implemented this so quickly: it's not that
'Nature gave it to you;' it was GeneXus that 'lent it to you.' You practically didn't
have to do anything! Dont give me that look, Diego. I was just joking So, is
your girlfriend coming over today?"
"Hmmm... We could also make another web panel (invoked through a Tab
from the countries View) that, for a given the country, would graphically display
the attractions for that country, as a gallery or sliding images. Id like to come up
with something very impressing" said Diego as he drifted into deep thoughts.
"Impress users Diego? I see that youre in a quite serious mood today. Before
you continue with your plans, remember we still need to call the web panel youve
just implemented from the Work With Countries."
"True, but you know how to do that. Just add a new action to the
predetermined ones (insert, update, etc.) in the instance of the Country Work With.
Then relate it to a button outside the grid and indicate that with this action the
newly-created CitiesPerCountry web panel is to be invoked."
Right-click the Selection (Work With Countries) node, select Add actions
and then repeat the procedure while positioned on the new Actions node. See the
effects of our friends operations upon execution:

78

web panel created


Button in the grid?

Image wanted for action


instead of button?

Requirement C is now ready!

New Tab in View Country


Diego wanted to impress someone (maybe you, dear reader) with a new
requirement: adding a new Tab control to the ViewCountry, showing the countrys
attractions in a gallery of images. It would be something that would look like this
when executed:

79

3 images will be on screen at all times, the one in the center being the active
one. Upon clicking on the right image, the one in the center moves to the left and
the one on the right to the central position (and becomes de active image), as a
new third image appears on the right.
To achieve this, Diego adds a Tab node in the pattern of the Work With
instance corresponding to the View, which will be loaded with the content from
another GeneXus object that Diego will have to program. It could be a web panel,
but in fact it needs to be an object that can be executed within another one (in our
case, within ViewCountry). Itll be a Web Component. To all other purposes, itll
be the same as a web panel. Hell call it AttractionsXCity and hell indicate, in the
new Tab, that it will be loaded with it.

CountryId must be passed as a


parameter to the Web Component
implementing the image gallery.

80

How to implement it. Another side to extensibility: User Controls


In addition to the standard controls you usually insert in your panels (attribute,
grid, text block, etc.), GeneXus X allows you to create your own customized
controls: user controls. Once a user control is installed, it can be used as any
standard control. GeneXus X includes certain preinstalled user controls (see the
toolbox in IDE; they are grouped under the label User Controls): ImageGallery
is one of them. In the photosetting below we can see that Diego inserted a control
of this kind in the web component form, for which he only had to set properties.
Upon inserting this control in the form, a structured data type, ImagesData, is
automatically created, better known as SDT, which allows building record lists of
variable length in a flexible way. In this case, a list of elements where each will
have the information on the attraction to be displayed. That is: the ID, the place
where the image is located (images are usually saved in large size and in small
size), and its description. Along with the SDT the &imagesData based on it is
automatically created, in order to load the images to be displayed.
The only thing that Diego had to do was program the load of that variable. And
how did he do that? In the Start event of the Web Component he wrote the
invocation of an object he created immediately, meant to load hierarchical data
structures, like SDTs. We will see this object type (Data Provider) further ahead. It
is not important if this code is not understood at this point. We just wanted to
show how easy it is to cover this requirement.

81

Consistent Look & Feel with no sweat?


Nowadays, having a consistent look & feel is a must for all Web applications.
Creating and maintaining each page in a Web application and ensuring
consistency throughout the site implies long programming periods, Julia read out
from a technology magazine she saw on Diegos desk.
"Not with Master Pages," added Diego. "Like I told you, a web panel can
implement an ordinary web page like the one we made, CitiesPerCountry (with the
Free Style and standard
grids).
That is, an independent
web page that will be
invoked by another one (in
our case, by WWCountry).
Or it can implement a web page that will be a component of another page, like that
of the image gallery, which was a Web Component in the ViewCountry. Or, it
could also be a master page, centralizing everything common to all the pages in
82

the site, such as the header and footer youve seen everywhere. It is usual for them
to even have a vertical menu on the left, so that it is only in one location and, if
you want to change it, you only need to do it once."
"Of course! At the start of the project I saw Mike running transactions that all
had the same header and footer (which I also see now in the Work With Countries
and the View Country), and I wondered how that was possible when those sections
weren't included in the objects' form. A master page programs that common look,
right?"
"Exactly. Take a look at this." Diego said
as he selected the Country transaction and
accessed its properties.
"You'll see the same in all transactions
and in the web panels created by patterns:
AppMasterPage is a master page created
automatically with the KB -watch the
content of the GeneralWeb folder- which
contains the header and footer found
everywhere.

Lets open this web panel and look at its properties. What does this tell you?
Here, apart from the common form, you can also program common behavior. It is
quite usual for pages to be restricted to authorized users, who must log into the
system to be able to browse through the sites pages. In the past, validation of a
user authorization had to be repeated for every web page accessed. However, with
master pages, the validation code only needs to be written once, here, and thats

83

it! We make sure that all associated pages will carry out this validation and that
codes will not be scattered everywhere."
"Thats great! I mean, for you, because less work is necessary for
achieving consistency. Im going out for lunch now, and then Ill impact the
pattern on the rest of the transactions we have. Did you have lunch already?"

84

Chapter 4

Flight to the World of Subtypes


The project was moving on as planned, with each member of the team focusing
on specific matters. Thanks to GeneXus' incremental philosophy, they felt
confident about facing changes or innovations to come. The model covered
everything necessary, just what was necessary.

Completing Transactions on the Fly


It was past lunch time, but Diego wasn't hungry. He decided to wait a while
before creating the rest of the transactions. The truth is, he had offered to show
Mary more of GeneXus in action, and wanted to brag about it. Instead of taking
his notebook to the coffee shop, he had suggested a meeting that afternoon in his
office at ACME.
"Hi, Mary, looking good! Hows it going?"
"Better thanks. I want to tell you that its very nice of you to invite me. After
all, we work for competitors. I really appreciate it!"
"Hmmm... It's not exactly as you say," he mumbled as he wrote 'the
Community' on the board. But, don't get me wrong: what I mean is that
competition isn't quite as you think in our case. You see, there are thousands of
GeneXus developers who are all linked by what's called the Community. It's
something very motivating, what many would call 'synergic'. If you imagine a
kind of club, there aren't any social or sports activities for now," he added with a
smile, trying not to sound nervous. "It's about interaction. Like a network for
sharing knowledge and solutions related to GeneXus and its related tools.
Thousands of programs and extensions have been created by Community
members to meet their different needs. And you'll find many web sites from where
you can download them and publish your own as well. The Community is very
active, and has created numerous forums where you can exchange all kinds of
solutions. I'm on several subscription lists and consider myself an active member."
"Sounds interesting, but... does it actually work? Do they really help you out
when youre in need, or is it baloney?"
"Like they say: 'Give today to receive tomorrow'. We all need a helping hand
every now and then. If we see each other as collaborators with a common purpose
rather than competitors, we can all benefit from working better and more

85

enthusiastically towards improved solutions. We share the objective of making the


Community grow for everybody's profit. It may sound naive, but the truth is that it
actually does work. Proof of that is the fact that GeneXus itself is made up of
GeneXus own extensions. That means that the Community may be the one to
expand GeneXus with their own extensions. In fact, GeneXus could be considered
as an extension in itself."
Diego was happy to see her bright, familiar look and felt confident to go on
with his explanation:
"Look," he said, as he opened the Extensions Manager window through the
Tools option in the GeneXus menu, "this is the current list of extensions in
GeneXus X. Most of them were developed by Artech and the rest by Community
members who made them available to everyone else."
"I see that the Start Page has a section called 'Extensions,' with an abstract by
the author and a link to install it," she pointed out.
"Yeah, and if you read it through, you'll notice that some of them don't include
the By Artech note. They are extensions created by third-party Community
members."
As far as the project was
concerned, at that point reality
required that more transactions be
added.
After a quick review, Diego
created the Airline transaction to store the names of airlines related to Travel
Agency & Co.

Flight Transaction: Destination: Subtypes


Diego read his notes and was glad to see that the next transaction was going to
be a complex one. Mary enjoyed challenges.
"To create the next transaction, you'll need a bit of concentration," he warned
her. "Take a look at this case. The transaction will contain flight information such
as description, airline, departure time, and maximum number of passengers; this
data is easy to understand and infer. We will also have departure and arrival

86

cities,32 both data from reality that we need to know and store. At the coffee shop I
mentioned that attributes that share the same concept must have the same name.
Remember that?"
"Yes, when you showed me how to create the Country transaction. I remember
there was an exception..."
"It's time to clear that up. Sometimes, we need to break the rule and use
different names for attributes that are basically the same, like in this flight
transaction. Every flight implies two countries and two cities, with different roles:
a departure country and city, and an arrival country and city. We have two
references to the same table, COUNTRYCITY. Look, if we only wrote this: as he
jotted the following lines on a paper,
We could say that the CountryId
and CityId attributes in the Flight
transaction represent a city in a
country, because they have the same
name as the Country transaction
identifiers.
This means that they'll be a foreign key of the COUNTRYCITY table. So far
so good, but now we need to add another city33 with another role: the arrival city.
In other words, a city has to be referenced twice: as departure city in one role and
as arrival city in the other. How do we do this? We won't be able to add one
attribute pair to the same transaction twice in GeneXus. And that is obvious
because how could those attributes be distinguished then? However, we could do
something like this..." He took a pen and added two new attributes; following
which he wrote a D before the first two (meaning Departure) and an A before
the last two (meaning Arrival).
"Hmm... But if GeneXus infers that they're
different things because they have different
names, there'll be no connection between flights
and cities, right?"
"Right. The solution is to tell GeneXus that these attributes are still the
same concept, despite the changes made to their names to be able to tell them
32

Since we're simplifying reality, we assume that there will never be more than one airport per city.
When we say "city" we always mean a real city, such as Paris. To identify a city, we must provide the
{CountryId, CityId} pair. Due to the transactions' design, there can't be any cities that aren't related to
their countries. For example, there's a city called Rosario in Argentina and another Rosario in Uruguay,
but Rosario doesn't exist as independent from a country.
33

87

apart. Though DCountryId is no longer called CountryId, it still has the same
function so GeneXus has to maintain referential integrity as before. This is the
same as saying that DCountryId is a subtype of CountryId.34 The complete
solution is to group these pairs into two groups of subtypes, see?" he said while
redrawing the diagram.
"Yes, I see...! Because of that,
DCountryId and DCityId will be a
FLIGHT
foreign
key
to
the
COUNTRYCITY table, just like
ACountryId and ACityId. You have two
foreign keys to the same table."
"Correct. And all referential integrity checks must be automatic," he added, as
he sensed a renewed hesitation in her. He wondered if he'd be able to take control
of the keyboard again.
"Anyway, the problem doesn't
end
here," continued Diego. "In this
transaction, besides indicating that a
flight has departure and arrival
countries-cities, we want to infer
each country and city name to view them in the form. We want to infer in order to
display attributes of the FLIGHT extended table. How can we infer them if we
have two references to the table? We can't use only CityName because there are
two of them. GeneXus wouldn't know whether to use the {DCountryId, DCityId}
foreign key, or the other foreign key - {ACountryId, ACityId}. There's an
ambiguity!"
Well, you'll also have to change the names of the (CountryName, CityName)
attributes to be inferred and put them in the corresponding subtype group, Mary
thought, and then said: "Show me how to define these groups in GeneXus; go
ahead, that way I will finally get it."
Diego selected Subtype Group from the New Object window and named it
Departure. Mary smiled and didn't say a word.

34

88

Thus, CountryId is a supertype of DCountryId.

"As I told you, they really


are groups. You create one,
name it and add the 'new'
attributes35 pointing to their
corresponding supertypes. In
this way, GeneXus will know
that
the
FlightDepartureCountryName attribute will be inferred only through the
FlightDepartureCountryId attribute, because they belong to the same group
Departure. See the connection?"
"Sure," she replied. "That means that when the user enters a value on the
{FlightDepartureCountryId, FlightDepartureCityId} foreign key, he will trigger
the referential integrity check on COUNTRYCITY, and also, this country-city
code's name will be inferred from the FlightDepartureCityName attribute, and the
country's CountryName will be inferred through the extended table in
FlightDepartureCountryName. Now we should create the arrivals subtype group.
Right?"
"Well, not necessarily, because the two groups are clearly separated. The one
I've just created is the explicit one. The other is implied if I add the CountryId,
CityId attributes to the transaction structure.36
But for the sake of clarity, in cases like this we use to group all occurrences.
Otherwise, one role (arrival) wouldn't be clearly identified. How if you create the
other group yourself?" asked Diego, pointing at his laptop.
"Ok, I'll give it a try..." said Mary, who was getting increasingly excited by
what she was learning and wanted more. She typed away until
35

Note that subtype names follow the GIK naming convention. That's why they begin with "Flight" (the
transaction's name), followed by "Departure" (the group's name). This ensures an easy understanding by
defining their roles in the transaction.
36
This ambiguity could be removed by simply changing the name of one of the two CountryId and CityId
occurrences.

89

"Great!" everything was ready for Diego to create the Flight transaction in
GeneXus. "It'll be a two-level transaction, for every flight has three separate
classes (First, Business and Economy) with three different fares, which
actually makes it a price list (1-n relationship). All flights have only up to
three different fares. Keep in mind that the flight ID must not be autonumbered because this number is defined by an international standard that
includes routes and time. For example, Pluna Flight 0174 from Montevideo to
Buenos Aires operates on Saturday mornings. If it's moved to the afternoons,
the flight number will change as well."
The figure below shows the final structure. Note the
icon that indicates a
subtype attribute, and also originates in a foreign key. The
icon indicates
the subtype in addition to the inferred one.

Maximum number of passengers for


the flight

Since the FlightClassId attribute can only have up to three possible


values (First, Business and Economy class), Diego created a numbered
domain for it.
The FlightDepartureTime attribute stores the flight time (the date is not
important). Note the DateTime data type. From it, only the part

90

representing Time will be used, so in the properties we will change the


Date format name property in the Picture group, to be None.

Before and After


To show Mary the new transaction running, he pressed <F5>, following which
he had to reorganize the database (three new tables were to be created).
Mary could not hide her disappointment.
Diego, who was very aware of all her
reactions, also found the form a bit hard to
get into, so he quickly proposed: lets fix
this form that doesnt look too friendly.
To enter a more user-friendly departure
country and the departure city, he could use
dynamic combo boxes or disguise the Name
ID (remember what he did on page 57) and
do the same with destination country and
city, as well as with the airline.

Lets start with countries and cities; we could


edit the properties of the FlightDepartureCountryId
attribute in the structure and modify its
ControlType property there (and do the same thing
for the rest) to Dynamic Combo Box.
So, in the ItemDescriptions property, exclaimed Mary you would need
FlightDepartureCountryName, where you want to infer the country name. That
way the names of countries from the COUNTRY table will come out as
descriptions in the combo.

91

Yes, if thats what you want. But, then youll have to add there the
CountryName attribute and not the subtype, because thats the attributes actual
name in the COUNTRY table, not FlightDepartureCountryName.
So, Diego typed CountryName in the
ItemDescriptions property and also
modified the value of the ContextualTitle
property
of
the
FlightDepartureCountryName attribute that
now reads Departure country. He did the
same
for
FlightDepartureCityId,
FlightArrivalCountryId
and
FlightArrivalCityId. Take a look at the form
now when Diego actually made no changes
in it.
He went on to do the same for Airline,
and also edited the grids properties in the
form by modifying the value of Rows, as he
changed it from 5 to 0. The value of this
property specifies the number of blank lines
presented in execution for the user to enter
data there. Note that it is not necessary to
have blank lines, because the [New Row]
under the grid allows the addition of blank
lines to the grid to fill them in with data.
Diego pressed <F5> to show Mary the after
running:
... when suddenly Mary announced that she had to
leave.
"Ill be going now Diego. Thanks a lot. Ill call you
soon."

92

An Actual Flight: FlightInstance Transaction


The Flight transaction handles general flight information; for instance, Pluna
Flight 0174 from Montevideo to Buenos Aires departs daily at 11:15 AM. For
each flight 0174, there'll be an actual plane flying on a given date, with a certain
number of passengers on board.
The following transaction represents the actual flight, with information such as
date and departure time, number of passengers, their reservations with names and
seat numbers. Here, the numerical identifier will be auto-numbered.

count(FlightInstancePassengerSeatNumber)

With this design, FlightNumber will be a foreign key. How many FlightInstances can
there be for the same flight (FlightNumber)? Is it as expected?

Some of the attributes here are worth noting. For instance,


FlightDepartureTime37 is the scheduled departure time of the flight (it's inferred
from FlightNumber). FlightInstanceDate and FlightInstanceTime are the actual
date and time of the actual flight. The actual flight time is initialized in a
predetermined manner with the value of FlightDepartureTime and can be changed
by the user. So, Diego created the following rule, which is executed only in Insert
mode:
default(FlightInstanceTime, FlightDepartureTime);

And he added another rule:


error('Number of passengers exceeded')
if FlightInstanceNumberOfPassengers > FlightTotalCapacity;

The FlightTotalCapacity attribute is inferred through FlightNumber. What


about FlightInstanceNumberOfPassengers? It's a formula that counts the number
of lines entered in the sublevel. Every time a new passenger is added to the form's
37

Even if the FlightDepartureTime and FlightInstanceTime attributes are of DateTime type (they allow
storing a date + time), we're only interested in time.

93

grid, a seat number (FlightInstancePassengerSeatNumber) is added for that actual


flight, and the formula is updated by adding 1. When a passenger exceeds the
maximum number, the error will be triggered so that no more passengers can be
entered into the database for that flight.
Lastly, Diego declares the rule:
error('The flight departure cannot be advanced')
if update and (FlightInstanceDate < FlightInstanceDate.GetOldValue()
or (FlightInstanceDate = FlightInstanceDate.GetOldValue() and
FlightInstanceTime < FlightInstanceTime.GetOldValue()));

In other words, when updating an actual flight, only the departure date and/or
time can be changed, as long as it's not set to an earlier date or time. Note that the
GetOldValue() attribute method is used, where the value stored in the database is
returned, whereas the attribute now has the value that the user has just entered in
the form (it's in memory, still unsaved).
Because passenger data will have to be stored, Diego will create the last
transaction for this stage and the PassengerId attribute will become a foreign key
in FlightInstance, and PassengerName inferred.

In the Flesh: Passenger Transaction

The following diagram represents the relationships between old and new
tables.

94

Diego pressed <F5>. Everything seemed alright, so he reorganized the


database. Then he accessed the Wiki, documented the end of this stage, and left
for Mike to do the testing and for Julia to apply the Work With objects to the other
transactions.

95

96

Chapter 5

When the "What" Is Not Enough


Just declare? What about Procedural Descriptions?
That's what Mary asked a couple of dates later, at the usual coffee shop. They
had started seeing each other more often, at his office or at the coffee shop, and
had discussed several topics such as patterns, web panels and so on. Today, she
was in a quiet mood. She understood that transactions allowed describing users'
views on data in a declarative way, but it didn't seem enough. She wanted to know
about the batch or similar processes that are needed in all applications, because
these processes can't be inferred from the knowledge provided by views on data.
"So?" she asked.
"A procedural language is missing, I agree," Diego affirmed. "Considering the
GeneXus philosophy, it'll probably be a very high level language. What's more, it
should only use references to the External Model, not to the Relational Model. For
instance, suppose that you must delay the scheduled departure time of all major
flights (which carry more than a certain number of passengers) from a certain
airport, at a certain time on a certain date, for whatever reason say, bad runway
conditions. You'll have to access all the FLIGHTINSTANCE records where the
FlightInstanceDate and FlightInstanceTime values match the date and time when
planes won't take off, and belong to flights that depart from a certain airport and
carry more than a certain number of passengers. In those records, you'll have to
replace the current values of FlightInstanceTime, and maybe FlightInstanceDate,
with the new ones. To do so, you could filter the 'Work With FlightInstance' by
those values. For each line (an
actual flight) displayed on the
grid, you'd have to call the
FlightInstance
transaction
in
Update mode and manually edit
the values. Most likely, this will
be unacceptable for end users. The
other alternative is to use variables
in a web panel (such as 'Work
With FlightInstance') for users to
enter both the current and new
date and time values for those
flights, as well as their country,

97

city and carrying capacity. Finally, an action (button or image) would call a
procedure that runs through the records and makes the change."
"Is it a common procedure?"
"Yes, it's a new GeneXus object type. We want the user to press the Change
flights button related to the Enter event in the web panel, to invoke this new
object.
Event Enter
ChangeDepartureTime.Call(&FlightDate, &FlightTime,
&DepartureCountry,&DepartureCity, &NewDate, &NewTime, &capacity)
EndEvent

Lets create it then!


A few seconds later, Diego was ready to create the Procedure object in order
to implement the previous logic.

The variables that appear here were declared by Diego as the procedures entry
parameters in the Rules selector:
parm( in:&CurrentInstanceDate, in:&CurrentInstanceTime,
in:&CountryId, in:&CityId, in:&NewFlightInstanceDate,
in:&NewFlightInstanceTime, in:&FlightTotalCapacity);

"Wait a second, I got lost. I assume that the For each is a command for
accessing the database by running through a table. But, where do you say that
FLIGHTINSTANCE is the table to be run through? Besides, you're using
attributes from another table. Shouldn't you run through FLIGHT first and, for the

98

records that meet the conditions, make a join with the FLIGHTINSTANCE
table?"
"That's not necessary," Diego replied. "To begin with, you don't declare the
table directly. That's the trick! In the For each command that we wrote,38 we said
that for each record of the table where the attributes mentioned are located
(FlightInstanceDate,
FlightInstanceTime,
FlightDepartureCountryId,
FlightDepartureCityId, and FlightTotalCapacity), the values of the first four
should match those of the variables received through the parameter. In addition,
the FlightTotalCapacity value should be greater than or equal to the variable that's
received through the parameter. In this case, the FlightInstanceDate and
FlightInstanceTime values should be replaced with the new ones."
"I still don't get it. Those attributes are in different tables. FlightInstanceDate
and FlightInstanceTime are in FLIGHTINSTANCE, but all the others are in
FLIGHT Shouldn't you run through?"
"That's right," Diego interrupted her. "But FLIGHT is in the extended table of
FLIGHTINSTANCE. In other words, for each actual flight there's a FlightNumber
(foreign key) that belongs to only one record of the FLIGHT table, which has one
FlightDepartureCountryId,
one
FlightDepartureCityId,
and
one
FlightTotalCapacity. There's an n to 1 relationship between FLIGHTINSTANCE
and FLIGHT. GeneXus doesn't need anything else: it'll run through the
FLIGHTINSTANCE table and access each record's counterpart in FLIGHT, by
making an automatic join to get the FlightDepartureCountryId,
FlightDepartureCityId and FlightTotalCapacity attribute values. Using this data, it
decides whether to keep the record to process it (provided that the
FLIGHTINSTANCE record matches the date and time indicated by the
&CurrentInstanceDate and &CurrentInstanceTime variables). The condition to
keep a record for processing is the And concatenation of all the logical conditions
you see in the For each command's Where clauses. Since we've talked of base
tables, we'll do it here as well: it's the table run through by a For each command.
Because GeneXus knows the relationships between tables and the attributes'
location when making the analysis, it can infer the data access without you naming
any table. As a consequence, you can change those attributes from one table to
another, without losing the procedure's description.39"
Why? It looks a bit like magic... I wouldn't feel safe programming in this
way."
38

Take a deep breath, dear reader; we don't want you to run out of air.
As long as the attributes belong to the same extended table; otherwise, GeneXus will give an error
saying that the attributes couldn't be related.
39

99

"Believe me Mary, there's no magic here. Let's look at the navigation report to
address your doubts and mine. Before executing a procedure to test it, the first
test is already done: it's the navigation report, which provides information about
the things that are making you nervous. That's why I never execute without
reading this report first. Ok, I'm not going to lie to you. Sometimes I don't read it
and regret it afterwards. Let's read together...
(For seeing only the navigation list, instead of <F5>, which will also build all
programs, the procedure tab may be right clicked to select the View Navigation
option).

Base table

See? It displays the For each command's base table, the order that it'll use to
process the data,40 and the index suggested to follow this order (if it exists).
Besides, it shows the navigation filters; that is to say, where it starts and finishes
running through the table. In this case, it'll run through the entire table. 41 Then,
Constraints (filters on the records to run through) are analyzed. Below you can see
that for each FLIGHTINSTANCE record a join is made with the FLIGHT table of
its extended table (to filter by FlightDepartureCountryId, FlightDepartureCityId
and FlightTotalCapacity). In addition, the FlightInstanceDate and
FlightInstanceTime attributes of the FLIGHTINSTANCE table will be updated.
Be honest, Mary. Tell me how much longer it would take you to implement this
40

The order can be indicated with the Order clause of the For each command. Since it hasn't been
indicated, there is no database index to optimize the search for records satisfying these conditions,
GeneXus assumes it's the primary key of the table to be run through.
41
If there was an index formed by {FlightInstanceDate, FlightInstanceTime, FlightDepartureCountryId,
FlightDepartureCityId, FlightTotalCapacity}, it would use it to optimize the query and avoid running
through the entire table. It would inform this in the Navigation filters of the Navigation report. In the
event that there was an index formed by a subset of those attributes, it would suggest it. That is: as long as
theres an index allowing query optimization, it will suggest it. (At any time you can have GeneXus
create a user index). We say that it'll suggest it because this information is valuable for SQL generators,
but actually, the DBMS determines the most appropriate access plan. On the other hand, it is vital for
non-SQL generators (RPG, COBOL, VB-Access, VFP-DBF).

100

with your current tools. You'd manually make this join. Really, it's best to keep
talking in a high level. Think about what would happen to your implementation,
which most likely will require you to name tables, if you moved the
FlightTotalCapacity attribute from FLIGHT to FLIGHTINSTANCE. Here, you
don't need to change anything at all. You just regenerate this object for GeneXus
to infer the new navigation, and that's it!"
"I see your point. But, how do you insert and delete records from the
database?"
"Well, the For each command allows you to run through a database table and
access its extended table not only to read but to update attributes. Thats why it's a
very important command that can be used not only in procedures but in every
GeneXus object that supports procedural code (such as transaction and web panel
events). For additions and deletions, two new commands have been created: New
and Delete."42
"Now that I think about it, the procedure doesn't control the same as the
FlightInstance transaction: advancing a flight's departure date and time is not
allowed. I remember there was an error rule that prevented it," Mary said.
"You're right..." he nodded. Something was obviously on Diego's mind, and
Mary looked at him expectantly. He fell silent for a few seconds and finally said,
"I'll have to add this control to the procedure by asking with an If command before
updating. Every time I change the date and/or time of an actual flight, in any
object, I'll have to redo the same control of the transaction rule, repeating the code
over and over. I might make a mistake or skip it altogether..."

A sure and easy way: the "what" of Business Components


"Since we know," he continued with renewed energy, "that transactions are
one of the most important objects, because thats where users views, business
rules and formulas are gathered, and the uniqueness and referential integrity
controls are executed, what would you say about reusing them from any other
GeneXus object?"
"Huh?!" the look on her face made Diego laugh.
42

Referential integrity is not checked in any case, allowing users to enter records pointing to nonexistent
records, or to delete records pointed by other records, thus orphaning them. Only uniqueness is checked.
These are programmatic controls, as GeneXus enables referential integrity checks at the DBMS level,
where controls will always be made.

101

"Thats right, reuse them, drawing on all the knowledge theyve incorporated.
For example, if I had a way of encapsulating all the logic of the FlightInstance
transaction, disregarding the interface that is, if we could have a buffer or
something, a temporary structure, like, for instance, a composite, structured
variable, where all the data (header and lines) of an actual flight could be loaded
I could enter it into the database from any object If the transaction's logic were
really encapsulated like that, the insertion would only be allowed if all the
conditions for entering that same information through the transaction were met
What I mean is: if I wanted to insert a flight instance associating a nonexistent
flight (FlightNumber) to it, or tried to add a nonexistent passenger, it would fail
and I wouldnt be allowed to make the insertion, just as would happen in the
transaction. Or, for example, if I want to add a passenger that actually exists but
whose incorporation exceeds the flights capacity, it wont allow me to perform
that insertion, just as it wouldnt allow me to do it through the transaction, as I
have an error rule in the transaction," Diego explained as he opened the
FlightInstance transaction and showed Mary the Rules section.
You, dear reader, can look this up in the previous chapter. So, its possible to
encapsulate the transaction's logic, retaining the structure, but discarding the form:
its called Business Component. It is a data type that GeneXus generates building
on a transaction.43
"And how do you go about encapsulating all that?" Mary asked. "How do you
use it?"
"With the transaction you want to use in this
other, 'silent' way, all you have to do is change the
value of its Business Component property to
'True.' Once you save this change, GeneXus will
create a new Business Component data type,
which will have the same name as the
transaction."
"But how do you use it?" she asked again,
intrigued.
"Through variables based on that data type.
Every time you want to update, add or delete a
flight instance, instead of using For each, New, and Delete, youll be able to use
all the possibilities provided by the FlightInstance transaction, through the
43

Business Components are obtained from transaction objects, but they can be used from any other
GeneXus object to add, delete or modify data in their tables.

102

properties and methods of a variable based on the FlightInstance data type


generated by GeneXus. Lets change our last procedure to perform an update
through a Business Component."
Diego went on with his monologue, while Mary waited expectantly, without
speaking. "We need a variable, &FlightInstance, of the data type generated when
we switched the Business Component property to 'True.' In it, we will put all the
content of the flight instance that we want to change. This variable will naturally
be structured; it will be the 'buffer' where well temporarily have the data of the
flight we want to manipulate at a certain time. The code will look more or less like
this " he said, replacing the two direct assignments in the object with the four
sentences we see in the image below. "Note how here we only use the For each
command to run through the base table and to filter, but we dont update directly.

"See? The first thing I do here is load from the database the flight instance to
be modified, in the &FlightInstance variable, according to the FlightInstanceId
value corresponding to the record that met the filter conditions in the For each
command (its the record of that iteration). Next, I change only the data that we
need to modify, and then I save, using the Save method. To edit a flight through
the transaction, you'd have placed the identifier in the forms FlightInstanceId
field, and then youd have left the field. To do that with the Business Component,
we use the Load method. In the transaction, you'd have changed the values of the
FlightInstanceDate and FlightInstanceTime fields in the form, and then clicked
[Confirm]. And in this case? You change the values in the variable, and then run
the Save method. What youll have as a result is practically the same thing. I
mean, what would happen if in the transaction you changed the flight to an earlier
date and time?"

103

"The error you programmed as a rule would be triggered, and it wouldnt let us
save. That is, the change you wanted to introduce in the record wouldnt be made.
The record would be left as it was."
"Exactly. And what do you think will happen here, in the procedure?"
"The same thing?" she asked.
"Right! The same thing! The rule will be triggered, and as its condition will be
met, it wont allow you to save the change."
"And how will I know what happened?"
"Well, in the case of the transaction, since its an interactive object, theres no
doubt there. A Business Component, however, is not interactive, so any messages
and errors resulting from the processing (executing the Load and Save methods, or
even the Delete method) must be stored somewhere. GeneXus places them in a
collection (list) of messages associated to the corresponding Business Component
variable, and you can retrieve this list with a method (GetMessages). Then you can
browse this list of messages But if you only want to know if any errors
occurred, you have the Fail method, which returns a 'True' value whenever theres
an error. So, in our case, youd write 'if &FlightInstance.Fail()'"
"I get it," Mary said. "And what other errors can occur when youre
manipulating data with a Business Component?"
"The same as when you try to insert through the FlightInstance transaction.
That is, referential integrity (if you tried to change the flight, FlightNumber, which
is a foreign key, for one that doesnt exist), uniqueness (if you wanted to insert a
new flight instance, and you assigned it a FlightInstanceId that already existed for
a different record), data type validations, error rules declared in the transaction and
whose triggering conditions were met"
"Of course! In this sense, its safer to have a procedure using a Business
Component. Besides, that way you know that all the business rules are going to be
triggered without having to repeat them."
"All of them?" Mary asked. "If you dont keep the visual interface, what
happens if the transaction has a rule that triggers a call to a web panel, for
example?"

104

"Well, ok, not all of them GeneXus ignores any rules in the Business
Component that employ user interfaces. The rule you describe wont be included."
"Interesting" she said.

Where are you getting at? Tempting attractions in PDF format


If youve been paying close attention, youve probably realized the same thing
Mary did (something she preferred not to mention until the right time came):
"Among the selectors of the Procedure type object theres a 'Layout' selector.
Whats it for? Can a procedure allow you to make a visual output?" she asked.
"Actually, it can. As it happens, one of the requirements our users have
included in their specifications is that the travel agencys site should have a page
showing attractions per city, and a link of the type 'View as PDF.' To do that, I
created a procedure, which Ive called AttractionsPerCity. Look," Diego said as he
opened the object in his notebook and selected Layout.

"Ill have to tell this procedure that it will have a PDF file as its output. The
idea of the Layout is to declare what I want to have in the output. As a result of the
execution, I want to display for each city, all the attractions it has. The user will
obviously have to have Acrobat Reader installed, in order to open from the
browser the PDF file that is generated. To indicate what is to be displayed in the
output, and the format it will have, the Layout contains print areas, which are
controls called printblocks. In color in the figure, you can see where two of these
controls start: City_Block and Attraction_Block. I gave them those names after I

105

added each control. Inside each printblock you enter the information (attributes,
variables, images, lines, boxes, etc.) that you want to display in that data area,
when its invoked from the code. For example, note how in City_Block Ive
included the CityName and CityInformation attribute controls, because thats the
information I want to display in the list for each city."
"And with that little bit of information GeneXus already knows what to list and
how?"
"Whoa! Mary, hold on. You cant expect it to do magic! With what weve
entered so far, it can't know how you want to list the information. We still have to
get to the code," Diego said, raising his eyebrows with a playful look on his face
that made his friend blush.
"Well, you make it sound so great it wouldnt surprise me if it could read
your mind." They smiled at each other.
"Can you read my mind?" Diego ventured, moving forward.
"How about you tell me?" Mary returned, staring straight into his eyes.
"Your wish is my command!" After a brief silence, he began again. "I want to
run through the cities, and the attractions for each of them. This entails using the
two nested For each commands."
Mary moved her chair closer to his, took the mouse from his hand without
asking his permission, and, smiling all the while, clicked the Source selector. The
window changed, and showed the following code:

106

Diego continued:
"Note that you dont need to set the filter by city for the second For each
command: thats because theres a direct 1-n relationship between the tables that
are run through, and this is one of the most common cases of nested For each
commands. The base table of the external For each command is COUNTRYCITY,
and the one for the internal For each command is ATTRACTION (because of the
attributes of the printblocks involved), and as GeneXus knows the relationships
between the tables, it implicitly applies the restriction over the records to be
retrieved. But its more powerful than that: it also finds indirect 1-n relationships.
For example, if you wanted to list, for each airline, the number of flight
instances."44
Mary didnt utter a word. She just looked at the screen. Still smiling, she rightclicked the procedure Tab and selected 'View Navigation' from the context menu.
Diego was looking at her. A new Tab appeared on the screen, with the following
window:

"See what I mean? Its restricting the search," he explained to Mary, who just
watched and smiled. "This is indicated by the navigation filters of the
ATTRACTION table in the second For each command. Note the @. Its
indicating that it takes those values from the context. What are the values for
@CountryId and @CityId? The ones from the record of the first For each
command it works with in that iteration. These are intentions that GeneXus does
discover indeed."
44

Between the AIRLINE and FLIGHTINSTANCE tables there is an indirect 1-n relationship (with the
FLIGHT table as intermediary). GeneXus finds indirect 1-n relationships in many other cases and makes
the join.

107

Diego went on:


To make this list executable you will have to change two properties: Main
Program = True, Call Protocol = HTTP for execution in the browser. You
will
also
have to include a
rule
in
the Rules
selector
output_file("AttractionsPerCity", "pdf"); where you are informing that the
output will be a pdf file, with whatever name you specify. You can also tell the
system to send the output to a printer in the computers scope from where the
browser is being executed with the application.
To execute it Diego moved to the tab with the procedure name and right
clicked on the Run with this only option for GeneXus to build and execute only
that procedure. Marys disgusted face was immediate. That listing only showed
data in no format at all. But Diego swiftly saved the procedure with a new name
and improved the design and the data that appeared on the screen

now he obtained the following in execution:

108

"You can also tell it to send the output to some printer within reach of the
computer running the browser with the application."
Finally, Mary broke the silence: "Paris looks tempting Why dont you come
over to my place for dinner tonight? And you can tell me more about it"

109

What about queries?


Another great achievement in GeneXus X is the Query object, which allows
creating queries to the database and improve the output of the data retrieved. The
latter can be viewed in various formats (bars, pies 3D or flat, areas, etc.) that
enrich applications. It also enables users to make dynamic queries (what measure
to see) through pivot tables, etc.
A query of this type is defined as a structure. Lets suppose that we want to
query the number of take-offs on a given date (FlightInstanceDate), per airline
(AirlineName), for each city (CityName). The following figure summarizes such
search:

We have named the Query object created from the New Object window
QSoldSeatsByArrivalCities. In the Attributes node we have inserted the
AirlineName and FlightArrivalCountryName attributes that we want to see during
running time. Immediately below we have declared the Count function, but,
depending on what is needed, a Sum and Average45 could also be declared.
We could also include parameters. In this particular case we have included a
variable based on a specific attribute.

45

Not all addition functions apply to all types of attributes. Sum and Average are only available for
numeric attributes.

110

We also have the Filters node, where if necessary- we will set the conditions
to retrieve the records to be shown. In this case it will be all records whose
FlightInstanceDate attribute value (included in FLIGHTINSTANCE) is equal to
the value of the parameter we have named &DepartureDate.
And lastly we have the OrderBy node, where -if necessary- we will have to
define the attribute(s) to be considered. In this case, the data will be shown in
alphabetical order according to the content of the AirlineName attribute.
Now, how do we execute this query? We must
create a web panel with our preferred appearance,
just like any other one, but in this one we will
have to insert the Query Viewer User control from
the Toolbox in the IDE.
We then access its properties and set the
necessary ones. In this case the Query property has been modified by assigning to
it the name of the Query object defined in the beginning
(QSoldSeatsByArrivalCities). The Type
property was also modified. Its purpose is to
establish one of the three possible output
types, namely: Pivot Table, Table, and Chart.
We recommend you try them to find the
differences between them. Take into account
that, for the Chart value you will also have
the ChartType property from where you can
select a style from among twelve
possibilities. And this is all you will need for
the basic construction of a Query.
In the SQL statement selector you will see
the code generated by GeneXus which will be executed on the database to obtain
the desired view as the web panel designed for that purpose is run.

111

Now <F5> and: voil!

112

Chapter 6

More to Declare
Knowledges new leading players: Data Providers
GeneXus goal is for you to declare, declare and declare. When you declare,
you indicate the what without worrying about the how, which changes over time.
We often discover new, better and more efficient ways for implementing. The
what is the essence, it remains stable. It is knowledge that enables automation. It
was common for transactions and business components to be the stars of
GeneXus: they declared the logic of the business. They declared knowledge. As it
evolved, at each stage, GeneXus found a new how. Now, a new leading player has
appeared on the scene: the Data Provider. For a wide range of cases, we will go
from programming procedures, to declaring data providers.
Intrigued? Mary was. Check out what happened.

Declaring?
Without answering the question she had left hanging in the air, Diego clumsily
opened his inbox and found an email message from the agency with a new
request: They wanted him to generate an interface file with XML format to send
out to a given airline containing the number of tickets sold per flight for that
airline on a given date.
Look, he said softly to Mary turning his notebook so she could read the
screen.
Piece of cake, she replied, taking her time to read it. Her eyes had lingered
on other messages, and Diego, realizing it, chose not to comment on it. You
just implement a procedure similar to the one we saw. But, what do you have to
do to generate an XML format output in GeneXus? Her inquiry was totally
logical, though her mind seemed elsewhere. What was she really thinking about?
Its not complicated at all. But you know what? This time, were not going
to begin with a procedure. Before the X, we didnt have a choice, but now we
have something more powerful for cases like these.
What do you mean More powerful?
Thats right. No procedural coding. Here, for example, you need to indicate
structured information. Imagine what the resulting XML would be like, for

113

example He went on to create an XML file and wrote the following to show
her:

Mary peered into the screen, frowning, her eyes half-shut, and Diego took this
as a sign of encouragement to go on with his explanation:
For this, were going to use a Data Provider, which is an object designed
specifically to return structured data. Let me show you something. If you wanted
to implement this request as a procedure in GeneXus, youd program something
like this:

See how in this code the input elements are all mixed in with the output
elements?
Now, never mind if you dont understand the code, just be honest and tell me if
you dont find it really complicated here to distinguish the resulting structure from
the way it is loaded?

114

Thats because procedures privilege the inputs transformation language to


obtain the output. So the output is obscured and difficult to identify. Data
Providers privilege the output instead. In fact, you declare your intention through
simple x = y type equations for each element of the hierarchic structure you want
to return loaded.
This is really interesting, Diego, but its getting late and I can see its going to
take a while
Just five more minutes! he said, trying to delay her departure as much as
possible. Mary hesitated for a few seconds and finally said:
Ok, go on, declare.
Diego created a new Data Provider type object, which he called
LoadNumberOfPassengers. Mary studied the image.

Yeah... It has almost the same selectors as the procedures.


Right, but the difference is in what you write in the Source selector, because
itll be a declarative code instead of a procedural code. But, lets go over it one
thing at a time. According to the request, some other object will capture the airline
number and the date from the user, and both will be received as parameters. So
lets define the variables and declare them in the Rules, which he went on to do:
parm(in:&AirlineId, in:&DepartureDate);
Right. Now we go to the Source, said Mary, pretty sure of what came next.
Well, no, not yet. We have to define a type of structured data, which will be
the data type of the information returned by the Data Provider.

115

A type of structured data? Like a struct in C, or .Net, or a record in Pascal?


Exactly. A structure that can contain simple data like other structures, and
also collections (lists) of data. It can even be a collection itself. In GeneXus, you
define such data types as objects, and not in the Domains windows (similar to how
you do it in Java, when you define classes that are later instanced). In our case,
well define a Structured Data Type object, which we can call simply SDT, and
well enter its structure there:

See? he asked as he hurried on with his explanation, This data type is made
up of three members, called Name, DepartureDate and Flight. The first two
will be simple data types, and the third will be a collection of items (see the Is
Collection checkbox), each of them structured. Weve called them FlightItem.
This last structured member is in turn made up of three members. As you can see,
since I gave the first two members the names of attributes in my KB, their data
type was inferred as being the same as that of the corresponding attributes with the
same name. I gave them the same name as the attributes because what Im actually
going to do later is load this SDT with the values of those attributes. But lets not
dwell on that now.
Seeing he had Marys full attention, Diego clicked on the name of the SDT
that was displayed in the Folder View Tree and dragged and dropped it into the
Source area of the Data Provider, with the following result:

116

Automatically, GeneXus initialized in the


Source the structure that to be returned by the
Data Provider; whats more: it gave a value to
the Output property that indicates what the
structure returned by the Data Provider will
be.
Now, all Diego has to do is replace the
Source
comments
with
the
values
corresponding to each member.

Mary was on the verge of uttering a but... when he quickly went on with his
explanation:
Wait, I havent finished yet. I still havent filtered by the received parameters.
Look at how I finish the Data Provider:

117

Where clauses like in the For each commands? Mary asked thoughtfully,
making the key connection.
Thats right. In the language of the Data Providers youll have groups, which
contain elements. In our case: SeatsSoldByFlight, Flight and FlightItem are
groups. The groups contain elements, variables, and/or other groups. In any case, a
group may appear at output only once or multiple times. GeneXus is smart enough
to determine this.
How?
You said it yourself. The attributes that appear to the right of the assignments
in the elements, and the groups where clauses, determine that group is like a for
each command, which accesses a base table.
If there were no where clauses, like in the Source before you added them, and
if instead of attributes to the right of the assignments you had variables or
literals
then in that case, in the output youd have the SDT loaded in such a way
that the Flight collection would be made up exclusively of one item. Instead, in
our case, the Flight group will contain many items, as many as there are flight
instances for that date and airline, and the root group SeatsSoldByFlight will
have a single item, because well be filtering by AirlineId.
Oh, I get it, said Mary, Its like having a pair of nested For Each
commands. The first, according to the attributes that appear, will go through the
AIRLINE table, and the second will go through the FLIGHTINSTANCE table.
Correct! Look at the navigation report:

118

Also, look here, to the right of the elements, you can put both attributes and
any functions or formulas that return a result containing the same type of data as
you defined for that element in the SDT. Thats why we use a count formula for
SoldSeats. Actually, since we already have that formula as global in the
FlightNumberOfPassengers attribute, we couldve just included the attribute
directly. I didnt do it because I wanted to show you that we could write any
calculations.
Now I understand why you said that Data Providers are declarative. What you
have to do is declare what the resulting structure will be, and then load it through x
= y equations, where you declare in y how x is calculated. Now, how do you
return the XML that you need?
Well, actually, you have to invoke this Data Provider like any ordinary
procedure, from any object, and do whatever you want with the output, for
example, make it an XML Diego answered, Let me just show you by doing it. I
think thats the best way for you to understand it.
Diego created a Web Panel and three variables: &AirlineId, &DepartureDate
and &SeatsSoldXML. The data type for the last one is LongVarChar, and it has 2
MB (itll contain all the information on XML format):

119

He then placed the cursor on the Events selector and wrote:

Wait, wait what about the &SeatsSold variable to which youre assigning
the data returned by the DataProvider?
Oh, I forgot to define it, he said as he took care of that. Your data type will
naturally be the returned SDT, that is: SeatsSoldByFlight.
Right, and I take it that the ToXML method applied to an SDT variable has
the effect of converting the SDT format content to XML format. Really?
Really. The true value in the parameter is only there to indicate that the
header must be added to the xml; but, that doesnt matter now then after the
method is executed, the information is contained in memory inside the &SeatsSold
variable.
Now all you have to do is generate, for example, a file with that content, and
youre all set, Mary added as she checked her watch to see the time.
Yes, and maybe even better: I can just send it directly by email to the airline
company.
Right Diego, listen, dont go on. I appreciate the explanation, but now I
have to go. Please dont be offended, but Im supposed to meet some people. Ill
see you at my house tonight. And well continue with the declarations Ok?

120

Sure, but I forgot to tell you that a Data Provider can also load and return a
business component, because the structure of a business component is similar to
the structure of an SDT. It can then be inserted in the database from the calling
object, with the Save method, as is normally done.
Ok, you can tell me all about it later. See you tonight, right?
After she left, Diego stayed at the table for several minutes with a dreamy look
in his eyes, taking in her perfume, which still lingered in the air.

121

122

Chapter 7

Winds of change
Straightening up the house: Categorization
That night, along with his notebook, Diego had brought the wine. The music
playing in the background created an extremely cozy atmosphere.
"You have to keep your promise," Mary demanded, smiling, as she filled her
glass with wine. "Tell me more."
"You mean about GeneXus? Well, I dont know what else to tell you" he
seemed nervous, but immediately got hold of himself. "Today, for instance, I was
categorizing the objects of the KB. I dont know if you remember, but the IDE has
a panel in the KnowledgeBase Navigator container called Category View, that
displays a tree with all the objects that youve classified, under their respective
categories. Give me a minute and Ill show it to you," he put the notebook on his
knees and his wine glass on the end table next to the sofa.
"Im not sure I see the point" Mary replied as she sat down next to him.
"Well," Diego tried to fill the silence as he started up
his notebook, "for example, in my company we usually
have categories to identify the status of objects:
'Operating,' 'Under Review,' 'Under Construction.' That
way, you can see the objects that are ready to be tested
with just a quick look, simply by opening the 'Under
Review' category. In this case, we divide our universe of
objects into separate categories. In fact, you can even
name this criterion for classifying your universe,
precisely with a category: 'Status,' for example,
containing these three subcategories. But, at the same
time, we might want to categorize the same universe
according to different criteria. What I mean to say is: you
can include the same object in several and distinct
categories. For example, suppose you also want to organize by system, subsystem,
etc. Nothing prevents your object from being in the category corresponding to a
subsystem and also in the 'Under Review' category in 'Status.' Or you can even
categorize objects according to where they will be used: in either the applications
back-end or its front-end. Categories allow us to organize and view the
information in our KB depending on our specific needs."
123

"Multi-categorizing" said she with her eyes shining intensely. Or at least


thats how they seemed to Diego.
"When, under the properties window, you select
an object from Folder View, you have a container
called Categories that starts with a small toolbar
where you can both add categories to the object and
eliminate categories from it. But, as always, theres
more than one road leading to Rome"
"Today you were categorizing that means you
had to go to every object, one by one, and assign
the corresponding category to each, right? Too
much work!"
"Yes," he replied somewhat embarrassed. "The thing is, categories are pretty
new, and Im not really comfortable using them yet, even though it was a
company decision to use status categories. Sometimes its difficult to change the
way youre used to doing things. We should have created these categories from
the very beginning, and the objects already with the 'Under Construction' category,
so that we could move them across categories as their status change. Today I had
to straighten up the house, because the objects in the KB were getting to be too
many. But I only had to do this for the 'Status' subcategories, because the 'To-Do
Diego' category is dynamic, and maintains itself."
"What do you mean?" asked Mary as she reached out for the wine bottle.
"In this case, as I had to straighten things out anyway, I put comments with the
text 'To-Do Diego' in some objects that were pending, just as others had done.
Then I created a dynamic category. Dynamic categories have a search condition
associated to them (that can be done by words or by properties, but we will see
that later). All the objects resulting from the search, become part of the category.
In the search condition, I indicated that it look for objects with the text 'To-Do
Diego,' and it found all the things I have to do quite a few, by the way Lets
see how that was done.

Seek and you shall find


Another interesting feature youll discover in GeneXus X is its capacity to find
"anything" in the KB. This feature is presented in the same way as when we use

124

search engines on the Internet. Based on complex algorithms, GeneXus Xs fulltext search engine finds what youre looking for among what could be tons and
tons of words contained in the objects that make up the KB. And like most search
engines, it allows us to use intuitive syntax to limit our searches. In the following
image you can see the To-Do Diego search

The full-text search engine browsed the KB and reported all the places where
the text was found. Note how, from this query, we can create the dynamic
category with the same name, "To-Do Diego," that Diego showed Mary above. To
do so, you just have to [Save as Category]. Maybe thats what Diego did that
day
Notice also, below, another search proposed, but in this case only of
properties. For example, if we wanted to locate all the objects of the procedure
type, we would need to add a property:

125

Foundation, mascara, eye-shadow Making up the application


That same afternoon, several hours earlier, Julia was finishing up the
documentation in the KB, when Mike, who was rounding up the testing, made the
following remark:
"I heard from Diego that they want to change the style of the pages. He was
too busy with some objects he had to finish developing, so he passed that chore to
me. He told me to talk to you about the details."
"Thats right. I got an email describing, more or less, the way they want it to
look, and I copied the instructions in the Main Documents Talk; Ill document it
properly later. They left it up to us to decide on the colors and all the rest. And I
had already saved their logo to the KB some time ago, in the Images node. They
want it to be located at the top of each page."
"I can do that right now. I just
have to open the AppMasterPage
master page created with the KB and used by default by all objects. This
centralizes the header and footer that will appear on all pages in the site then I
replace the default 'Application Header' and its all set. To do everything else
they asked for, we should call Paul, the graphic designer"
"But Paul doesnt know anything about GeneXus, and youre going to let him
open the objects and modify the controls in the forms, changing the color, size,
and everything else?!"
Mike laughed: "Julia, look, we should each stick to what we know. Id never
let him touch our objects! But I need him to configure the design for each control
in the forms. For example, I need him to specify the size, background color, font,
etc., for the transaction buttons, as well as for the grids and other controls. Id like
to centralize that so that he wont have to touch the controls 'in' the objects. Thats
what we have the Theme type object for. See, here, in the Themes node, under
Customer in Folder View, we have one called GeneXusX. Its the one GeneXus
associated by default to our objects. If I open it, youll see that its a list, in tree
format, of classes of controls (although its not merely that)."

126

Heres where design


aspects
are
configured for this
class.

Each control type has several possible classes. In the Button class theres a
subclass, BtnDelete, which by default inherits its properties, but it allows you to
change them. If we now take any transaction and edit the form, in the properties of
the [Delete]
button well
be able to see
the
ones
associated to
this
class.
You
can
change it for a
different one.
With this, you completely separate the behavior from the design in your
application. And look here, what Im going to do now is export46 the GeneXusX
theme from our KB, send it to Paul so that he can configure the appearance of the
classes and send it back to me, so that I can then import it, and voila! Design
applied! Paul doesnt need to have GeneXus, just the Theme Editor, which is a
utility program that only allows you to work with these objects. Its a specific tool
for graphic designers. Another option is to do it from within GeneXus."
In fact, now that I see it, the companys logo is
colored orange, so we could use Orange as the Theme
name (we do that by marking a check in the check box)
and lets do a Save as TravelAgencyTheme. This way
we use one that is totally our own. This one we can send
to Paul. To show you how, lets change the colors of
some classes in the theme, following which he changed
46

We hadnt talked yet about exporting/importing in GeneXus. In this book we will only say that you can
export GeneXus objects and other types of knowledge from a KB, in files with an xpz extension, which
can later be imported into another or the same KB. For that we have an option in the Knowledge
Manager menu.

127

properties in the Grid, FreestyleGrid and Table classes (with the


TravelAgencyTheme new theme open), and then saved it. What I have to do now
is instruct the KB47 to use the theme in all objects:

And having also changed the AppMasterPage web panel, after requesting that
GeneXus rebuild all programs (Build/Rebuild All) to consider that now objects
will have this theme, note what it looks like under execution. For instance, if we
look at the WorkWithAirline, and then the transaction to modify an airline:

The Master Page and Theme object types are the most important when it comes to
designing the applications appearance.

47

Actually, to the KB version active at the time. For further details on KB versioning await the coming
episodes or the numerous GeneXus documentation sources.

128

Tell me when and Ill tell you the way you were
Another interesting possibility offered by GeneXus X is that of seeing how
objects in the KB evolve over time. That is, each object will have a history
associated to it, where changes will be recorded with date and time, along with the
ID of the user who made them. This allows monitoring of an objects evolution
from its very creation.
And whats more: you may go back to a previous version of the object by right
clicking to select that version as active. In this next image

you can see, on the left, the content of the Latest Changes View panel, and, on
the right, the history of the Airline transaction. Note how there were six changes
since the date it was
created; therefore there
are
seven
version
numbers. You will also
be able to compare two
versions and see the
differences between them. For example, you could select two versions with a right
button click on Compare Selected Revisions. As a result of comparing revision
12 against 14 of the Country transaction, GeneXus will display the differences in
two adjacent windows as shown below for the example (there were no defined
rules in version 12).

129

KB versioning?
The inexorable passing of time caused advances that Mary and Diego were
seemingly unaware of.
Diego inquired Mary.
Yes Mary?
Dont you think the time has come for as she tidied her skirt with both
hands, she cleared her throat before she continued talking after a few seconds that
seemed ages to him making a copy of the KB?
Oh! Backup copies? Well, that is actually something extremely easy to do in
GeneXus. In fact, within the KB you can have pictures of different statuses of
the KB throughout time. And not only that; you can also have parallel
developments of various versions. For example, you want a version in production
and go on developing new requirements, so that you can later make corrections to
the production version as the user requires it, without interfering with the main
development.
Very interesting! But you can go on with the explanation later, ok? she got
up and, standing in front of the sofa with her hand extended towards him, said
Come.

130

Recurring situations: to avoid repeating always the same, Data


Selectors
It is commonplace to codify the same situations (filters and orders for DB
access) in different parts of an application where data is recovered and the same
logic (or a part of it) is scattered here and there.
Upon considering the following code bits:

and compare them, its obvious that different results are obtained through them,
although with the same bit of logic: they both want to filter by African cities
(CountryWorldRegion=WorldRegion.Africa), sorting them by name. The first one
displays exactly that in the output (lets suppose that City_Block contains city
attributes), and the second one displays the attractions of the African cities in the
"Safaris" category. Note the code block they have in common, formed by an order
and a filter. There could be dozens of GeneXus objects where youd need African
cities ordered by name.
A Data Selector allows you to centralize and reuse navigations, thus avoiding
code duplication.

But it has more advantages. New members of the development staff are often
unaware of the common criteria or filters of an application. For example, suppose
that tourism to Africa is being actively promoted; as it usually happens, someone
who is asked for a list of cities gets one with all cities instead of only African
cities. Centralizing these criteria greatly shortens the learning curve, allowing staff
to quickly become productive and reducing the number of mistakes.
In the previous example, if we gave these common clauses a name, as if they
were a macro that could later expand wed have a Data Selector! A name for a
data search criterion. In our case: AfricanCities.

131

The above procedures would then be as follows:

The Using clause, which says to use the content of the AfricanCities Data
Selector, is written to the right of the For each command; and thats all If we
change the criteria later on, we do so inside the Data Selector object and it's
automatically changed everywhere!

The path of processes


People are very good at a lot of
things, but not exactly in tasks such as
searching for a document among
hundreds of others, being on top of
when each document is due, and
making sure the work thats completed
is channeled from one place to another
according to a predefined sequence. Or
are we?
GXflow, a well-known Artech tool
connected with automation of company
processes, by determining task flows, is
also integrated into GeneXus X. Why?
Applications have increasingly more
process flows, which require Workflow

132

components.
Now you will be able to create your own diagrams within GeneXus IDE,
greatly simplifying integration tasks, and connecting activities with KB objects
more easily. In this image weve designed a simple example that shows the
process flow for flight reservations.
The reservation itself, expressed by the first box in the diagram, is no other
than the start-up of the transaction it represents. A given condition -such as, for
example, if the data is correct and complete- is then evaluated. For illustration
purposes, lets say we have the following conditions
Print Tickets IF FlightStatus = AUTHORIZED
Get in contact with Client IF FlightStatus = CORRECT PERSONAL INFORMATION

These conditions are expressed through a conditions editor. The idea is that
rules be expressed, where the name of the succeeding task is indicated first,
followed immediately by a condition that must be met in order to continue
down that path. Simple, practical, and powerful.

If the condition is met, the ticket is printed and sent to the passenger.
Otherwise, the flow detours to the Get in Contact with Client task, a data updated
is performed (probably through the transaction corresponding to clients), and then
the flow goes back to the reservation, for the cycle to be restarted.

Back and Front End - Intra and Inter Net


In this book, we took the liberty of peeping into some private moments of our
characters lives, and this allowed us the possibility of seeing how some parts of
the application have been implemented. The goal: to see a bit of everything.
However, we havent seen the full picture yet. At times, we, the authors, feel a
little ashamed of our voyeurism, and we look away, to later feel tempted again to
turn our eyes back to the story. This is why weve seen objects that will be used in
the applications back-end (for example, Work With objects, as the data for
airlines, countries, cities, flights, passengers, etc., can only be updated by
company employees, with permits, through the Intranet) mixed in with other
objects that can be used in the applications front-end, that is, on the web site that
will be consulted by people around the world through the Internet.

133

But Diego, Mike and Julia have done much more work than what weve been
able to see so far. Theyve created the home page for the Intranet, slightly
modifying the home page created by the Work With pattern. Theyve added a
login section in the master page, web panels with various queries and different
menus.
In fact, that very afternoon, before his date with Mary, while Paul was given a
theme to modify, Julia contacted users of the Travel Agency, and Mike finished
testing, Diego was carefully examining how the home page of the companys web
site finally looked:

Notice that hotel, car rental and weather information is provided. These are
third-party applications, published as Web Services that can be easily integrated
(consumed) within GeneXus with the new object type called External Object. At
this point the reader has all the elements necessary to have an x-ray of the page
and guess what might be found behind it: a web panel, web components, master
page, theme, images, controls and so on.

The End or the Beginning?


So far weve obtained different pieces of a puzzle that you will be putting
together, drawing on whats most important: your imagination.

134

Based on it you will be able to discover the remaining pieces of the puzzle in
what will be a continuous and infinite search. The puzzle is always nearly but
not quite finished. Thats where its secret lies: in keeping us permanently in
suspense, searching, thinking, imagining and changing.
Friends, lets move forward with faith, with joy, with generosity,
with the synergy of this Community. Lets preserve the magic.
Breogn Gonda, Closing Address, 16th GeneXus International
Meeting
September 20, 2006

What do you think happened with our characters in the story? Was the
development project successful? How did that dinner with background music end?
Was Mary finally persuaded to join the Community? Pieces that are still missing,
and that each one will find like the secrets that are still brewing in the X
Age
Or could it be that this story is only just beginning?

135

Back cover
"I have to admit that, at first, the books casual style took me by surprise. Having read it
attentively, I now find that the "casual style" is yet another great idea that the authors have
had. I consider this book a very significant contribution to the knowledge of the Version."
Breogn Gonda, Engineer
Artech President
Diego and Mary run into each other after many years. Long gone are the days and nights of
studying, laughing and talking in the classrooms and hallways of the School of Engineering,
when Mary was always so full of life and Diego would let himself be carried away by her
laughter. Until the unexpected re-encounter brings memories back to reality.
Diego, Mike and Julia have three weeks to develop a web application for a travel agency,
including the application's back-end and front-end. Mary is going through a difficult time
professionally; she's a project manager so overburdened by maintenance chores that its
affecting her health.
GeneXus is the thread that interweaves the characters' journey through these pages.
Discovering and showing. Showing and discovering. Over and over again: GeneXus X.

136

You might also like