In the attribute list of a class, derived attributes are denoted by the prefix /
.
If you hover over a derived attribute, a tooltip shows the expression that defines it. If you select it, all attributes used to define it are circled in red; vice versa, if you select an attribute involved in at least one expression, all derived attributes calculated from it are circled in blue.
In the example in figure, the value of the /weight
attribute on the Shipping_component class is calculated by multiplying the value of the quantity
and /unit_weight
attributes (circled in red); from it is then calculated the value of the /total_weight
attribute on the Shipping class (circled in blue), which reports the total aggregate weight on all Shipping_component objects associated with a Shipping.
You can edit the expression used in any derived attribute by right-clicking on it and choosing Edit expression
from the context menu.
Restrictions #
Derived attributes depend on other attributes in the database. Because of this, it is not possible to perform some of the operations normally allowed with native attributes:
- changing the data type;
- defining integrity constraints (e.g. making the attribute required);
- defining an unique constraint (i.e. with
Make Unique
); - imposing domain restrictions.
Types #
Livebase supports two types of derived attribute:
- Math, calculated using a mathematical expression that can contain references to other attributes in the same class;
- Query, calculated based on the value of an attribute present in a related class (connected with a relationship or a path of relationships).
Math attributes #
A math attribute is an attribute whose value is calculated using a mathematical expression defined through the Math expression editor.
Create a math attribute #
Right-click on a class to open its Class menu
and select New derived attribute
> Math
. The Math expression editor opens and you can write the math expression to calculate the attribute.
The Math expression editor #
The Math expression editor allows you to define expressions, in which you can reference the value of other attributes present in the same class.
The icons in the lower right corner allow you to insert the elements of the expression by choosing them directly from a drop-down menu. Let’s see them in detail:
- opens the list of attributes of the class for which the expression is being defined; previously defined derived attributes and enabled platform attributes are also included;
- opens the global list of Enum classes and shows the literals defined in each one of them it is disabled if there are no Enum classes in the engine model;
- opens the global list of Singleton classes and shows the attributes defined in each one of them; it is disabled if there are no Singleton classes in the engine model;
- opens the list of User properties, i.e. information relating to the current Cloudlet user at the time the expression is evaluated. These correspond to the default attributes of the _User class (such as
username
,timezone
, etc.). In the expression, the current user is represented by the__CurrentUser
variable; - opens the list of System properties, i.e. system information such as current date and time, all depending on the configuration of the Cloudlet. In the expression, the system itself is represented by the
__System
variable; - opens a list of constants;
- opens a list containing mathematical and logical operators;
- opens the function picker.
Function Picker #
The Function picker collects a set of utility functions for defining expressions, including ensemble/mathematical functions or operators on dates and strings. Selecting a function from the list shows its description, which includes the required input parameters with the corresponding data types. Click on Show Examples
to see examples of how each function is used.
Example of math attribute #
If you place the cursor over a math attribute, a tooltip appears showing the expression that defines it.
In the example shown in the figure, the attribute /age
, which determines the age of an employee (Employee), has been selected; to do this, it uses the native attribute date_of_birth
to calculate the difference in years between the current date and the employee’s date of birth. Let’s now see in detail how this calculation takes place.
The expression uses the function dateDiff(d1,d2,calendarField)
, where d2
is the term in the expression that is subtracted from d1
:
- the current date (
__System.date
) was inserted in place ofd1
by selectingdate: date
from the system properties; date_of_birth
was inserted in place ofd1
, selecting it from the list of attributes;- since age is normally expressed in years, the expression must return an integer number (
integer
) that expresses the difference between the two dates in terms of years; to do this, thecalendarField
has been replaced withfield.year
.
At the end of the insertion, the message Expression has been validated as INTEGER
confirms that the expression used is valid.
Note that also /full_name
is a math attribute. This attribute was created by defining an Object title over multiple attributes. More information about this operation is available in the dedicated paragraph.
Query attributes #
A query attribute is computed from the value of an attribute present on a different class from the one on which it is defined, and it is connected to the class of interest through a relationship or a path of relationships. The attribute pointed to by the query is called the target attribute, while the path of relationships being traversed is called path.
By selecting a query attribute, the corresponding target attribute is highlighted in red. Conversely, by selecting an attribute involved in a query, all attributes defined from it are circled in blue. This mechanism allows us to know the path taken by the query to reach the attribute.
There can be multiple paths connecting the class on which the query is defined and the class of the target attribute. The reachability of the classes does not depend on the navigability of the roles: it is sufficient that a relationship exists between two classes for it to be navigable in both directions.
Positioning the cursor over a query attribute, a tooltip appears showing the expression that defines it, as shown in the following figure:
In the example, instead of persisting information about an employee’s city of residence (Employee) using a native attribute, we chose to model the cities independently, as objects of class City. To associate an employee with a city, it is therefore possible to use the derived attribute /city
, which has as its target the attribute name
present in the City class.
Create a query attribute #
Right-click on a class to open its Class menu
and select New derived attribute
> Query
.
Alternatively, select the target attribute, drag and drop it onto the class where you want to create the query and select Link here
from the context menu.
The Designer chooses the default name of a query in this way:
- if the role has to-one cardinality, the default name is RoleName_AttributeName;
- if the role has to-many cardinality, the default name includes the aggregation function used at the top;
- in either case, if the source attribute is the only attribute of that class, roleName is omitted.
The Query expression editor #
Below Path section is a list of all attributes that can be reached from the source class by browsing its roles . From here you can select the target attribute of the query by expanding its path. The attributes of the source class are not selectable.
Each attribute type is represented with a different icon: native attributes: , attributes math: , attributes query: .
The path selected by the query is also given in text form (e.g. city_.name
). This string can be edited to manually change the query path.
Query on multiple values #
A query whose path traverses at least one to-many role will retrieve multiple values for the pointed attribute, one for each object of the class involved in the relation; it is therefore necessary to define how to aggregate this set of values to represent them in a single attribute (e.g. concatenating the values, summing them, selecting the maximum value, etc.). Depending on the data type of the pointed attribute, the Aggregation function
dropdown presents several options; the table shows all available functions:
Function | Meaning |
---|---|
Count all | The attribute contains the count of records found. |
Count distinct | As above, but does not include records with duplicate values. |
Concat (comma separated) | The attribute is a string containing all the values of the found records, separated by commas. |
Concat distinct (comma separated) | As above, but does not include records with duplicate values. |
Max / Min | Returns the maximum/minimum value among the found records. |
If the source is a numeric attribute, additional operators are available:
Function | Meaning |
---|---|
Sum | Returns the sum of the values of the found records. |
Average | Returns the average value of the found records. |
Standard deviation | Returns the standard deviation between the values of the found records. |
For Boolean attributes we also have:
Function | Meaning |
---|---|
Logical AND | Returns TRUE if all records are true, FALSE otherwise |
Logical OR | Returns TRUE if at least one record is true, FALSE otherwise |
Queries with filtering conditions #
It is possible to filter the records found by the query in a way similar to what happens in a SQL WHERE
clause, by defining a filtering condition (filtering condition) through an expression; this is useful especially when the query retrieves multiple values.
Clicking on the Add filter
button of the Query expression editor opens an editor essentially identical to the Math expression editor, with one important difference: the expression of a filtering condition must always return a boolean value (TRUE
or FALSE
). If the expression is correct, the editor displays the message Expression has been validated as BOOLEAN
and allows you to confirm the entry.
When the expression uses only one Boolean attribute directly, the result will simply depend on the value of that attribute; in such cases you can avoid writing <AttributeName> = true
and use <AttributeName>
directly.
Example of query attribute #
In the following example, we want to determine how many projects (Project) have been completed by an employee (Employee).
The completed
attribute on Project represents the status of the project: the value TRUE
is equivalent to saying that it has been completed.
The /completed_projects
query in the Employee class points to the name
attribute of class Project. The association has a to-many cardinality (an employee can be assigned to multiple projects), so we need to aggregate the data with an operator in order to represent it with a single attribute. From the Query expression editor, the COUNT_DISTINCT
option was therefore selected as Aggregation function. This resulted in a count of all projects assigned to an employee.
To complete the definition of the query, it is necessary to exclude from the count all projects that have not yet been completed (for which the completed
attribute is equal to FALSE
). To do this, we set the condition Project.completed=true
.
To complete the definition of the query it is necessary to exclude from the count all the projects not yet completed (for which the attribute completed
has therefore value FALSE
). To do this, we set the condition Project.completed=true
.