Entity DSL

From OS.bee documentation
Revision as of 13:10, 3 August 2016 by Mollik (Talk | contribs) (id)

Jump to: navigation, search

Copyright Notice

All rights are reserved by Compex Systemhaus GmbH. In particular, duplications, translations, microfilming, saving and processing in electronic systems are protected by copyright. Use of this manual is only authorized with the permission of Compex Systemhaus GmbH. Infringements of the law shall be punished in accordance with civil and penal laws. We have taken utmost care in putting together texts and images. Nevertheless, the possibility of errors cannot be completely ruled out. The Figures and information in this manual are only given as approximations unless expressly indicated as binding. Amendments to the manual due to amendments to the standard software remain reserved. Please note that the latest amendments to the manual can be accessed through our helpdesk at any time. The contractually agreed regulations of the licensing and maintenance of the standard software shall apply with regard to liability for any errors in the documentation. Guarantees, particularly guarantees of quality or durability can only be assumed for the manual insofar as its quality or durability are expressly stipulated as guaranteed. If you would like to make a suggestion, the Compex Team would be very pleased to hear from you.

(c) 2016 Compex Systemhaus GmbH

Purpose

The Entity DSL facilitates the handling of persistence entities. Defining entities using the Entity DSL efficiently creates a clean entity model that contains all relevant semantic elements of the model text file. This semantic model is used to automatically transform the semantic information into proper Java code with the respective annotations for a persistence provider. Additionally, if the entity model is located within a project with OSBP nature, "Auto-DTOs" and services are generated as well. In this case, attributes that are added to entities will automatically be transferred to the "Auto-DTOs".

Overview

The main semantic elements of the Compex Entity DSL are the following:

  • "Package" - the root element that contains all the other elements. A model can contain multiple packages.
  • "Import" declarations - used to import external models or even Java classes.
  • "Datatype" declarations - a way to define datatypes that can be used in entities and beans.
  • "Entity" - the abstraction of a business model entity. It contains further elements such as properties and references.
  • "Bean" - does not compile to a JPA Entity but to a Java Bean (POJO with getter and setter and PropertyChange-Support). Beans may be used as temporary containers in entity operations or can be embedded into JPA Entities.
  • "Enum" - the abstraction for Java enums.
  • "Property" - a reference to an embedded Bean, an Enum, a Java class or a simple datatype (as defined in the datatype declaration). Offers multiplicity.
  • "Reference" - a reference to another Entity (or to another Bean in the case of a Bean). Offers multiplicity.
  • "Operations" - similar to Java methods. The Xbase expression language can be used to write high-level code.
  • "Annotations" can be placed on Entity, Property and Reference.
  • "Comments" can be added to all elements.


Entity model files

Entity models are described in .entitymodel files. These files describe the entity model and are the basis for the code generation. Entity models may be split over several .entitymodel files containing packages in the same namespace. An .entityodel file may contain several packages with entities. However, from a performance point of view, a complex entity model may work better with more and smaller .entitymodel files than the same model crammed into few large files (or even a single file).

package

Entity model files must start with a package declaration. Packages are the root element of the Entity DSL grammar. Everything is contained in a package: Imports, Entities, Beans and Enums have to be defined inside the Package definition. One document can contain multiple packages with unique names. The elements a package can contain are Entities, Beans and Enums. Additionally, a package allows Import statements and the declaration of datatypes.

 package name {
    import importStatement;
    datatype datatypeDefinition;
    entities/beans/enums
 } align alignment
Figure 1 - Entity model file - a package is the topmost element and contains other items.

import

The Entity DSL allows to reference entities defined in different packages, even in different .entitymodel files. The import statement is a way to make these elements available by their fully qualified name.

Import statements allow the use of the "*"-wildcard.

 import importStatement;


Figure 2: Items contained in another package can be addressed if the package is imported using the import keyword and its fully qualified name.

datatype

The Entity DSL allows the definition of datatypes. These are translated by the inferrer into their standard Java representation. The behaviour of the generator can be controlled by the datatype definitions. Datatypes defined in an .entitymodel file are local to this file. In order to define datatypes in one place and have them available in multiple .entitymodel files, the datatypes may be defined in a ".datatypes" file containing only datatype definitions inside a package statement. There are three types of datatype definitions:

  • jvmTypes: Datatype definitons that map types to jvmTypes take the basic syntax of datatype <name> jvmType <type> as primitive;.
Specifying datatypes in this manner uses an appropriate wrapper class in the generated Java code; adding the keyword as primitive enforces the use of primitive datatypes where applicable:

datatype foo jvmType Integer; compiles to an Integer whereas datatype foo jvmType Integer as primitive; results in int.

Figure 3: The defined datatype is translated to a wrapper class.


Figure 4: By adding the as primitive keyword, the datatype is translated to a primitive datatype.


  • dateTypes: The datatypes for handling temporal information can be defined by the following statement:
datatype <name> datetype date—time—timestamp;

Datatypes that have been defined in this manner can be used as property variables in entities and beans.

Figure 5: Defining datatypes for handling temporal information. Content assist is available.
  • blobs: Binary blobs can be handled by defining a datatype with the as blob keyword. The Java implementation of such a blob is a byte array. Appropriate persistence annotations are automatically added.

datatype <name> as blob;

Figure 6: Including binary blobs by using a datatype with the as blob keyword.

After import statements and datatype definitions, the content of the .entitymodel file is made up of entity, bean and enum definitions.

Entities

Entities are the most complex elements in the Entity DSL. An entity is an abstraction above a business object. Entities are defined by its name and properties, references and operations. Generally, an entity is an object which can keep a state about variables and references and can persisted. For each entity that is defined in a package, a Java class and the corresponding persistence structure is automatically generated. Inside a project with Compex nature, "Auto-DTOs" and services are created as well.

Entities may extend other entities. In this case, they are derived from their parent entity. That means that the properties and references of the parent entity are inherited.

Syntax:

[modifiers] entity <name> extends <parentEntity> {
    [entityProperties]
}
Figure 7: Items contained in another package can be addressed if the package is imported using the import keyword and its fully qualified name


Entities may be defined with certain modifiers that change the generated Java Code. The following modifiers are supported:

abstract

abstract marks the entity to be abstract. This generates an abstract Java class.

Figure 8: The abstract keyword causes the translation into an abstract Java class


historized

historized marks the entity to be historized. Historized entities can have several entries in a database, but only one of them may be marked as current.

The historized keyword adds an object ID (OID), a version field and a flag for the current version to the entity.


Figure 9: The historized modifier triggers the creation of an OID, an object version and a flag for marking the current version.


cacheable

cacheable marks the entity as cacheable. The appropriate annotation for the persistence provider is added to the generated Java code.

Figure 10: Declaring an entity to be cacheable adds the @Cacheable annotation

timedependent

timedependent marks the entity to be time-dependent. An object may have several entries in the database. Which entry is valid will be determined by valid from and valid until fields that are added to the entity. An object ID is created in order to tie the entries together. The timedependent keyword recognizes the modifiers (DATE) and (TIMESTAMP). Default is timedependent(DATE).

Figure 11: The timedependent keyword causes an object ID, a validFrom and a validUntil field to be created in order to support multiple database entries for an object.

mapped superclass

mapped superclass marks a class that provides persistent entity state and mapping information for its subclasses, but which is not an entity itself.

Typically, the purpose of a mapped superclass is to define state and mapping information that is common to multiple entities. All the mappings from the mapped superclass are inherited to its subclasses as if they had been defined there directly.

Figure 12: The mapped superclass keyword sets the appropriate annotation which causes the persistence provider to move the mappings to the derived subclasses.

Entity Persistence Settings

Apart from the mapped superclass modifier that moves all property columns to the tables belonging to derived classes, the following settings for table inheritance can be chosen within an entity definition:

  • inheritance per class
  • inheritance per subclass

The structure of the database created from an entity model can be controlled by the following settings:

  • schemaName
  • tableName
  • discriminatorColumn
  • discriminatorType
  • discriminatorValue

Inheritance per Class

inheritance per class causes a table to be created for each class; subclasses share this table using a discriminator value. This statement has to be followed by braces inside of which further details can be specified.

Figure 13: A single table for entity Base is created; the generated Java code for the “Derived” class shows that the “Derived” entity is added to this table by using a discriminator.

Inheritance per Subclass

inheritance per subclass causes a table to be created for each subclass. This statement has to be followed by braces inside of which further details can be specified. This is the default behaviour if no inheritance strategy is specified.

Figure 14: An @Table annotation is added to the generated Java code, so that the "derived" entity is mapped to a table of its own.

schemaName

schemaName allows the specification of a name for the database schema to be used. This setting is translated to the appropriate JPA annotation @Table(schema = <xyz>). The schema name given is converted to snake case using capitals.

tableName

tableName allows the specification of a name for the table (within the database schema) which the entity is mapped to. This setting is translated to the appropriate JPA annotation @Table(name = <xyz>).

The table name given is converted to snake case using capitals. The default value is the name of the entity.

Figure 15: Specifying the schemaName and tableName settings in an entity controls the name of the database schema and tables used for persistence.

discriminatorColumn

discriminatorColumn allows the definition of a name for the discriminator column in the case of inheritance per class. Can be set within the braces after the inheritance statement and has to be followed by a semicolon. Defaults to DISC.

discriminatorType

discriminatorType allows the definition of the datatype used as discriminator within the single table. Can be set to CHAR, INT, STRING or INHERIT. Can be set within the braces after the inheritance statement and has to be followed by a semicolon. Defaults to STRING;.

discriminatorValue

discriminatorValue allows a custom value to be used as discriminator within the single table. Can be set within the braces after the inheritance statement and has to be followed by a semicolon. Defaults to the entity name converted to snake case.

Figure 16: The inheritance statement allows the specification of discriminator column, type and value to be used in the case of a single table.

Beans

Beans are objects that are embedded in other entities, inheriting their persistence and lifecycle. Similar to Entities, Beans are characterised by their name, their properties and references. For each bean that is defined in a package, a Java class is automatically generated.

Beans can be embedded into entities by defining them as properties of the respective entity. The appropriate annotations (@Embeddable, @Embedded, @AttributeOverrides etc.) are added in order to have beans persisted with their parent entities.

Figure 17: Beans can be embedded in entities and are persisted with them.

Enums

Enums are an abstraction above the Java enum. They compile to enum classes and can be used as properties in Entities and Beans.

Figure 18: Defining enums allows using them as variables in entities and beans.

Properties

Properties of Entities and Beans are references to datatypes or enums. They can be regarded as variables and are defined by a keyword followed by a datatype (Java type or datatype defined in the datatype section) and a name. By defining a Bean as a property of an entity, it is embedded in it.

Properties can be determined with the following keywords:

var

The basic property var defines a variable that is persisted in a table column. A property must have a type and a name.

Multiplicity of properties can be controlled by the following (optional) settings:

  • [1] defines a non-nullable property.
  • [0..1] defines a nullable property (Default behavior).
  • [1..*] defines a list of properties that must not be empty.
  • [0..*] or simply [*] defines a list of properties that may be empty.
Figure 19: Variables can be defined using the var keyword.

The appropriate persistence settings are genereated automatically. If a multiplicity is given, the appropriate annotations (and, if necessary, a list rather than a single variable) are generated.

derived

derived defines a property that is derived from other properties. The derived property must be given a type, a name and the logic that derives it from the other properties, written as a Xexpression in braces.

Figure 20: Properties may be derived from other properties using an Xexpression.

The code is automatically translated to valid Java code.

dirty

dirty defines a flag that can be used to track the "dirty" state when editing values before the changes have been written back to the database. Only one dirty flag is allowed per entity. The datatype has to be boolean.

Figure 21: The "dirty" flag is used as a marker if changed have been made, but not yet written back.

The boolean field for this and the appropriate annotation are generated with the dirty keyword.

domainDescription

domainDescription defines a property that is used as a domain description. The appropriate annotation is added to the property. A domain description must be of type String. Domain descriptions may be derived from other properties.

Figure 22: Domain description properties can be created with the domainDescription keyword.

domainKey

domainKey defines a domain key. The appropriate annotation is added to the property. Primitive datatypes may be used as domain keys.

Figure 23: A field containing a domain key is created with the domainKey keyword.

id

-- deprecated -- deprecated -- deprecated -- deprecated --

id defines an id-property (used as primary key by the JPA compiler). This keyword is deprecated. If no id is given, a warning is shown.

Caution: ID autogeneration causes problems since the value is not set before the entity is persisted in the database. It is advised to use the uuid keyword instead.

Figure 24: Entities are supposed to have an ID property that is used as primary key in the database.

Caution: The generated IDs are not necessarily unique if the deprecated id keyword is used!

id

index causes an index for the table to be calculated. Indices may be based on one or more properties (primitive only) and references (one-to-one only) of the entity. An index must be given a name and, in braces, a list of the fields it is based on. If the index keyword is prefixed with unique, a unique index is generated.

Figure 25: Indices for the database tables that map entities are generated with the index keyword.

The @Table annotation is supplemented with the index definition.