Enumerations
Attribute values can be primitive (string, integer, date, ...), complex (i.e. an instance or instances of other classes e.g. Address), or enumerations which allow you to provide a list of localizable values e.g. Title = Mr., Mrs., Dr., ... that typically appear in drop-down lists.
Learning Objectives
This lesson introduces Enumerations and how to use them as attribute types in classes. By completing this module, you will learn:
- How to use Enumerations in your models.
- How NexJ Studio allows you to store captions to allow for translation of strings.
- How to use an associated class that does not make use of the reverse attribute.
Key Concepts
Enumerations are a special type of Class that provide a list of values along with localizable captions. They represent lists of values with localizable captions. They are a design-time and run-time concept, meaning they are created in NexJ Studio and are part of the Model, but are also loaded into database tables for use and modification at run-time. They provide a standardized way to create lists of values, like the days of the week, and localize them or associate them with UI elements like combo boxes. They can also be associated in a parent child relationship such as country and state.
Create the training:LanguageEnum enumeration
Enumerations are created in NexJ Studio as part of the Model. However, at run time, the enumeration values are also loaded into database tables for use and modification.
In this lesson, you create an enumeration called training:LanguageEnum
, that stores the names of four different languages. You then define both English and French values for the enumeration.
Users of your application may choose to work in either the English or French locale. When someone working in the French locale is asked to set a Person's preferred communication language they are presented the choice of anglais, français, espagnol, chinois, or italien. Someone working in an English locale would have the choices English, French, Spanish, Chinese, and Italian.
Create the new enumeration:
- In the Navigator, select Business Model/Enumerations. A list of the available enumerations is presented. As with other model elements, enumerations defined in the base model appear with grey icons. Enumerations defined in the model that you are editing appear with color icons.
- Right-click in the navigator and select New Enumeration.
- In the New Enumeration window, set the name of the new enumeration to training:
LanguageEnum
and click Finish.
The Enumeration editor opens. You configure enumerations by supplying a type code, classification settings, and association properties to other enumerations. - Go to the source tab and paste the following code
Paste this XML into the source tab or enter the information manually as follows
<Enumeration description="Languages spoken by people." typeCode="TSLANGUAGE">
<Locales>
<Locale caption="Spoken language" description="Spoken language" name="en"/>
<Locale caption="Langue parlé" description="Langue parlé" name="fr"/>
</Locales>
<Values>
<Value hasBehavior="true" name="ENGLISH" value="en">
<Locales>
<Locale caption="English" name="en"/>
<Locale caption="anglais" name="fr"/>
</Locales>
</Value>
<Value hasBehavior="true" name="FRENCH" value="fr">
<Locales>
<Locale caption="French" name="en"/>
<Locale caption="français" name="fr"/>
</Locales>
</Value>
<Value hasBehavior="true" name="SPANISH" value="es">
<Locales>
<Locale caption="Spanish" name="en"/>
<Locale caption="espagnol" name="fr"/>
</Locales>
</Value>
<Value hasBehavior="true" name="CHINESE" value="zh">
<Locales>
<Locale caption="Chinese" name="en"/>
<Locale caption="chinois" name="fr"/>
</Locales>
</Value>
<Value hasBehavior="true" name="ITALIAN" value="it">
<Locales>
<Locale caption="Italian" name="en"/>
<Locale caption="italien" name="fr"/>
</Locales>
</Value>
</Values>
</Enumeration>
Switch back to the Overview tab and you will see something like...
If you were to enter the enumeration information by hand, you would do the following. Since we pasted the source in, this is for information and reference only.
- Enter the Description
Languages spoken by people
. - Set the Type Code property to T
SLANGUAGE
. This uniquely identifies the enumeration and is used when persisting the enumeration and its values. - Set the Classification property to
system
. This specifies that the enumeration values are intended for use in the business logic and not exposed in a user interface. - In the Locales list, click the Add button to add two locales. Add locales and captions for English (en) and French (fr):
- The first has a default Locale value of en. Set its caption to
Spoken language
. - Set the second's locale value to fr and set its caption of
Langue parlé
(To type theé
character, hold down the ALT key and type the ASCII code 130 on the numeric keypad.)
These values serve a similar purpose as the Caption value did for your classes, acting as a label for the enumeration.
- The first has a default Locale value of en. Set its caption to
In the Values list, click the Add button to add the following four values to the list:
Values to add to the training:LanguageEnum enumerationName Value Has Behavior Code Updateable Display
UpdateableENGLISH en true false true FRENCH fr true false true SPANISH es true false true CHINESE zh true false true ITALIAN it true false true Setting Has Behavior to true allows you to write code that accesses the enumeration values directly, and base business logic on them.
Select the ENGLISH row.
In the Value Captions list area, click the Add button to add the following two captions:
Value captions for ENGLISHLocale Caption en English fr anglais Now select each of the other values in turn, and set their captions as follows:
Value captions for FRENCHLocale Caption en French fr français (ç = ALT+135)
Value captions for SPANISHLocale Caption en Spanish fr espagnol
Value captions for CHINESELocale Caption en Chinese fr chinois Value captions for ITALIAN
Locale Caption en Italian fr italien - Save your changes.
You have now defined two possible captions for each of the four values that this enumeration can take on. The caption that displays is based on the locale setting at run time. For example, if the value of the enumeration is set to zh (CHINESE), and my locale settings are set to English, then the caption is displayed as "Chinese". However, if I am working in a French locale, the caption is displayed as "chinois".
More about enumeration classifications
There are four behaviors that you can define for an Enumeration by setting its classification property.
system
Values are created at design time and only used in code for business logic. Values never get displayed in user interfaces.
sysDisplay
Values are not editable at run time, and are critical for business logic and system behavior. Values can be displayed to the user through user interfaces.
sysEdit
Values are critical to business function, but certain aspects can be modified at run time.
custom
Values are added at run time by users.
Using an enumeration as a complex attribute
Now that you have created the enumeration, you can use it to create a complex attribute for the training:Person
class.
To add an enumeration to the training:Person
class:
- Open the
training:Person
class for editing. - In the Attributes tab, add a new attribute called
primaryLanguage
with a Type oftraining:LanguageEnum
. Leave all the other attribute properties with their default values. - Save your changes.
Review the class diagram
View the model changes that you have made by expanding the training:Entity diagram.
- Open the training:Fundamentals diagram. (Business Model → Diagrams)
- Right-click the class name of the
training:Person
class and select Unhide Attribute → primaryLanguage. - Click the primaryLanguage attribute and drag it onto a blank area on the diagram.
- Rearrange the diagram so that you can see all of the elements clearly. It should now resemble the following picture:
- Click the Save button in the toolbar to save your changes.
Persistence Mapping
Enumerations are not persisted the same way as classes. Instead of having a Persistence Mapping tab, enumerations are automatically persisted in the EnumDisplay table. All you need to do in the logical persistence is add a column to the class that uses the enumeration and create a virtual index on that column.
Up until now, you have configured class persistence mapping first, then performed any further configuration in the logical data source. This time you first define the logical persistence for the new attribute, then you map the attribute.
Because the training:Person
class is persisted in the Entity table, you edit the logical definition of the Entity table to persist the primaryLanguage
attribute:
- In the Persistence layer, click the Data Sources tab.
- Double-click training:DB to open it and select the Entity table.
In the Columns tab, add the following column:
Column to add to the TrainingEntity tableColumn Name Type Allocation Allow Nulls Precision Case Insensitive primaryLanguage string varying true 50 false In the Indexes tab, create the following index:
Index to add to the TrainingEntity tableName Type Unique Index Columns Entity.FK_Language virtual false primaryLanguage The index is virtual and does not result in the creation of any index in the database. It serves as a logical link between the values of the attribute and the
EnumDisplay
table that stores the values of all enumerations.- Save your changes.
Update the class persistence mapping
Edit the class Persistence Mapping for the training:Person
class:
- Open the training:Person class and select the Persistence Mapping tab.
- In the Attribute Mappings section, click the Select Attribute Mappings button and add
primaryLanguage
to the list. Set the Source Key, and Destination Key values for the
primaryLanguage
attribute as follows:
Association attribute mapping for the Person classAttribute Source Key Destination Key primaryLanguage Entity.FK_Language EnumDisplay.SK1 EnumDisplay.SK1
is a virtual index in thevalueCode
column of theEnumDisplay
table, in which the enumeration's possible values and captions are stored.- Save your work.
Now, when the value of theprimaryLanguage
is persisted for thetraining:Person
class, a pointer to the appropriate row of theEnumDisplay
table is stored in theEntity
table. The values and their captions, however, are persisted in theEnumDisplay
table.
Edit the upgrade file
Add a new set up upgrade steps to update the data source.
Update the upgrade file:
To update the upgrade file:
- In the Persistence layer on the Data Sources tab right-click the training:DB datasource and select Generate Upgrade Steps.
- Leave the default values for Upgrade and Current Data Source.
- Select Old Model as the Old Data Source. You are going to use a published model as the old model.
- Select Published Model JAR and then click the browse button. Select the model you published at the end of the last lesson and click Next.
- Whenever you upgrade a database, you must increment the version number by a whole number. For example, if the version retrieved from the published JAR file is 4.36; change the Version to
5.36
. - Enter the following as the Description:
Added the primary language enumeration as an attribute to the Person class.
- Even though virtual indexes are not persisted in the database, the Upgrade Steps list contains a CreateIndex TrainingEntity.FK_Language step. This step makes no changes to the database. It is included to allow the upgrade process to know the state of the metadata as accurately as possible and improves validation and other code.
Load the training:LanguageEnums enumeration
You now need to add an upgrade step to populate the enumerations from the model into the data store. The platform automatically reloads enumerations from the model into the data source when the data source's loaded
flag is set to 0. You need to set this value to 0 to cause the enumerations to be loaded.
The enumerations are in the DefaultRelationalDatabase datasource so we need to create an upgrade for that datasource.
To load the training:LanguageEnums
enumeration:
- In the Upgrade Steps list, click Load.
Set the version to 7.1092.1307.167.53
- Click Finish to save your changes.
To complete the upgrade file modification update the model version from the Model Library to match the latest upgrade version.
Publish and upgrade
Complete the development cycle by carrying out the following activities:
- Optionally Publish the Model
- Upgrade the database
Test your work
When Model Server starts up, it automatically applies any system upgrades if the store's loaded flag is 0. Run the Server Console.
To test the enumerations in your model, use an existing or create a new scratchpad and test your persistence with the following code. Run it one command at a time.
; Obtain the value for the enumeration with the name ENGLISH
(training:LanguageEnum'ENGLISH)
; Obtain an instance of the training:LanguageEnum enumeration where the name is ENGLISH
(training:LanguageEnum'get'ENGLISH)
; Obtain the caption value of the ENGLISH instance of the enumeration
((training:LanguageEnum'get'ENGLISH)'caption)
; Define a new person instance with a primary language of English. Note that the primaryLanguage attribute is assigned an instance of the enumeration.
(training:Person'new
(: lastName "Wren")
(: firstName "Terg")
(: initials "L")
(: primaryLanguage (training:LanguageEnum'get'ENGLISH))
)
(commit)
; Define p as a shorthand to the instance that you just created.
(define p (read-instance training:Person '() '(= lastName "Wren") '()))
; Obtain the value of the primary language attribute, which is the ENGLISH enumeration instance.
(p'primaryLanguage)
; Obtain the value of the caption of the p class' primary language.
((p'primaryLanguage)'caption)
; JavaScript Version...
#"training:LanguageEnum".ENGLISH
#"training:LanguageEnum".get(#"string->symbol"("ENGLISH"))
#"training:LanguageEnum".get(#"'ENGLISH")
#"training:LanguageEnum".get(#"'ENGLISH").caption
new #"training:Person"({lastName : "Wren", firstName : "Terg", initials : "L", primaryLanguage : #"training:LanguageEnum".get(#"'ENGLISH")})
commit();
var p = #"read-instance"(#"training:Person", null, scm("'(= lastName \"Wren\")"), null);
p.primaryLanguage
p.primaryLanguage.caption
To see how the captions that are returned change depending on your locale:
- Stop the console
- Change the Windows Regional Options of your system to French (France).
Restart the Server Console and rerun the following commands, one at a time:
CODE; Obtain the value for the enumeration with the name ENGLISH (training:LanguageEnum'ENGLISH) ; Obtain an instance of the LanguageEnum enumeration, where the name is ENGLISH (training:LanguageEnum'get'ENGLISH) ; Obtain the caption value of the ENGLISH instance of the enumeration ((training:LanguageEnum'get'ENGLISH)'caption) ; Define p as a shorthand to the instance that you just created. (define p (read-instance training:Person '() '(= lastName "Wren") '())) ; Obtain the value of the primary language attribute, which is the ENGLISH enumeration instance. (p'primaryLanguage) ; Obtain the value of the caption of the p class' primary language. ((p'primaryLanguage)'caption) ; or in JavaScript #"training:LanguageEnum".ENGLISH #"training:LanguageEnum".get(#"string->symbol"("ENGLISH")) #"training:LanguageEnum".get(#"'ENGLISH") #"training:LanguageEnum".get(#"'ENGLISH").caption var p = #"read-instance"(#"training:Person", null, scm("'(= lastName \"Wren\")"), null); p.primaryLanguage p.primaryLanguage.caption
Info
When the caption is returned, you receive the French value.
- Stop the console and return your regional settings to English
To get an understanding of how the enumeration has been persisted in the database, query the training
database with the following queries:
Microsoft SQL Server
select * FROM NJEnumDisplay WHERE typeCode IN ('TSLANGUAGE')
select id, classCode, firstName, lastName, companyId, businessNumber,
primaryLanguage from TRNEntity where lastName in ('Wren')
In particular notice the following features, which result from using the Class Table pattern of persistence:
- The typeCode identified the rows of the NJEnumDisplay table that pertain to the enumerations. You can see this more clearly by removing the WHERE clause from the select statement.
- The value stored in the primaryLanguage column of the TRNEntity table is the value of the enumeration. This is due to the persistence mapping you created that linked the Entity.FK_Language key and the EnumDisplay.SK keys.
Info
When using the scratchpad editor, on a new line type (Lang
and then press Ctrl+Space. This enables Code Assist which makes writing code much easier. It allows you to inspect possible code completions, view function documentation and it provides function signatures. Code Assist is available in all Scheme editor areas within NexJ Studio.Assist which makes writing code much easier. It allows you to inspect possible code completions, view function documentation and it provides function signatures. Code Assist is available in all Scheme editor areas within NexJ Studio.