Annotations

Core Mapping Annotations

These annotations establish the structural bridge between the Java Virtual Machine and the relational schema.

  • @Entity Target: ElementType.TYPE This annotation is mandatory for any class intended for full CRUD operations or relationship support. It marks the class as a managed domain object.
  • @Table Target: ElementType.TYPE Optional if the class name matches the database table name. Use the name attribute to specify the exact table name when they differ.
  • @PrimaryKey Target: ElementType.FIELD Designates the unique identifier for the entity. EzQu enforces a single-field primary key constraint.
Attribute Type Description
GeneratorType enum Developers must specify the strategy using the value attribute:
  1. IDENTITY: Relies on database auto-increment columns.
  2. SEQUENCE: Uses a database sequence object to produce the ids. Use in conjunction with the 'seqName' attribute.
  3. UUID: EzQu will generate an id as a unique UUID. Needs a java field of a java.lang.String type with a varchar underlying column type or java.util.UUID with a Binary underlying column type. When table is generated by EzQu it is taken care of automatically.
  4. NONE: The default. This would mean the developer needs to handle the id outside of EzQu, and make sure it is unique. (Developer may use a trigger for this, but EzQu is not aware).
seqName String when using sequence the name of the sequence to use
  • @Column Target: ElementType.FIELD Configures specific database column properties. This is required for schema generation or when mapping to non-standard column names.
Attribute Type Description
name String The database column name.
length int Maximum length (e.g., for VARCHAR).
precision int Precision for numeric/decimal fields.
unique boolean Generates a unique constraint during table creation.
notNull boolean Generates a NOT NULL constraint.
sqlType String Overrides default mapping (e.g., mapping String to java.sql.Clob).
enumType int Used for Enum mapping. Set to Types.ENUM_INT for ordinal persistence (higher performance).

Basic Annotated Entity Example:

@Entity
@Table(name = "SYSTEM_USERS")
public class User {
    @PrimaryKey(GeneratorType.IDENTITY)
    private Long id;

    @Column(name = "USER_NAME", length = 50, notNull = true, unique = true)
    private String username;

    @Column(enumType = Types.ENUM_INT) // Persists ordinal for performance private
    UserStatus status;

    @Column(sqlType = "java.sql.Clob")
    private String bio;
}

Relationship Mapping & Depth Control

EzQu supports four primary relationship mappings.

  • @One2One: Defines a direct link. Defaults to Eager loading. Supports @Lazy and @Cascade(CascadeType.DELETE).
  • @One2Many: Maps a collection. Defaults to Lazy loading.
Attribute Type Description
childType java.lang.Class Optional - the class type of the related object. Inferred by the generic type if exists.
childPkType java.lang.Class When using a relationTable to maintain the relationship, the other side of the relation primary key field java type could be named here. If not named EzQu will attempt to find it, or fail to set up the relation table.
joinTableName String the name of the DB table maintaining the relationship. (when it is maintained in a relation table and not by Foreign Key). Default no relation table
relationColumnName String Relevant only when using a relation table, since when using a Foreign Key the relation is maintained in the child table and ezQu knows this from the child type. The name of the column representing the other side of the relation. If not present EzQu will use the simple java class name of the child entity.
relationFieldName String The name of the field in the many side object holding the other side of the relationship.
If left empty ezqu will assume that either there is a field on the other object which has a name identical to 'this' tableName or there is a column in the Db with 'this' tableName.
Note
  1. When uaing a relation table this is the nameof the column representing the parent object in the relation table.
  2. In a single sided relationship, when not using a relation table, a column FK must exist in the child table, even if it does not exist in the object. In such case, instead of a field name on can write the column-name.
orderBy String Optional - the name of a column in the other side of the relation that determines the order of the response
direction String Optional - when using orderBy this denotes 'ASC' or 'DESC'. Default is 'ASC'
cascadeType enum Only Cascade Delete is supported. Default is CascadeType.NONE, which means the related objects are not deleted when parent is deleted.
  • @Many2One: Used on the "many" side to fetch a parent entity. Often the inverse of an @One2Many. When One2Many is managed via FK it is not necessary to use this annotation (On many occasions this field won't even exist). This annotation should only be used with relation tables.
  • @Many2Many: Defines a many-to-many link via a join table. These relationships are always two-sided and always use lazy loading.
Attribute Type Description
childType java.lang.Class Optional - The class type of the related object. EzQu is usually able to deduce this from the generic type
joinTableName String The name of the DB table maintaining the relationship. Default no relation table
relationColumnName String The name of the field in this object representing the other side of the relation. Must have value! This will also expect (or create) a column with the same name in the relation table.
relationFieldName String The name of the field in the target object holding the other side of the relationship. If null 'this' tableName will be used!. This will also expect (or create) a column with the same name in the relation table.
childPkType java.lang.Class The other side of the relation primary key field could be named here. Correlates to the relation table. If not present EzQu attempts to find it. or fail
orderBy String the name of a field in the other side of the relation that determines the order of the response. (field must exist and be annotated in other class)
direction String Optional - when using orderBy this denotes 'ASC' or 'DESC'. Default is 'ASC'

Complex Relationship Example

@Entity
public class Project {
    @PrimaryKey(GeneratorType.SEQUENCE, seqName = "PROJ_SEQ")
    private Long id; // Ordered O2M relationship using a relation table

    @One2Many(joinTableName = "PROJ_TASK_LINK", relationFieldName = "PROJ_ID", childType = Task.class, orderBy = "priority", direction = "DESC")
    private List<Task> tasks;
}

Inheritance Mapping

EzQu supports two inheritance strategies. Developers MUST use @Inherited on the child entity to define the strategy.

  • @Inheritence: Used to mark the inheritance strategy to be used for an object graph when persisting it to the underlying RDBMS. Set the annotation on the root class of the object graph
Attribute Type Description
inheritedType enum Determines how the inheritance is mapped to the persistence store. In both cases there is a single table. One with Discriminator the other assumes only a single object is mapped per table (TABLE_PER_CLASS).
Table per class (Default): Every concrete subclass is mapeed to its own table containing all inherited and local fields.
Discriminator: A single table stores the entire hierarchy, differentiating by a discriminator column.
discriminatorColumn String Only when inherited type is 'descriminator'. The name of the column used to store the descriminator
discriminatorTableName String The name of the table representing the whole object graph when using the discriminator strategy. If not supplied the name of the table will be the same as the table of the root class in the object graph.
For TABLE_PER_CLASS strategy this parameter is ignored.
  • @MappedSuperclass : Applied to abstract classes to prevent EzQu from creating a dedicated table for the superclass.
  • @Inherited: Use on an inherited class when the inheritence strategy is Table per class.
  • @Discriminator : Use this annotation when your entity is a child type in an inheritance graph and the inheritence strategy is discriminator, to define the discriminator for this class. No need to use the {@link Inherited} annotation.
Attribute Type Description
discriminatorValue char A discriminator char denoting 'this' type in the table

Advanced Field Control

  • @Cascade: Used on One2One relations when you want cascade delete behavior when deleting the Entity
  • @Lazy: Used on One2One relationships you want to lazy load.
  • @RelationTypes: Used on One2One relations when the related entity type is 'abstract' and you need to tell EzQU which child classes to except.
  • @Converter: Bridges custom Java types and DB types. Requires a class implementing EzquConverter. There are some default converters a developer can use in com.centimia.orm.ezqu.converter package.
  • @Version: Enables optimistic concurrency. Applied to Long or Integer fields. EzQu will throw an EzquConcurrencyException if a version mismatch occurs during update.
  • @Transient: Fields ignored by EzQu but visible to standard serialization. (Note: Java transient keyword is ignored by both).
  • @Extension: Fields only populated via "extended select" queries.
private class Person {
    @PrimaryKey(GenerationType = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    private String lastName;

    @Extension
    private String fullName;

    public Person() {}
        ... Getters and Setters
    }
}

normal work with Person object will not populate fullName, it will simply be ignored. But you can do this:

List<Person> res = factory.getFromSession(select -> {
    Person p = new Person();
    select.from(p).where(p.getId()).is(3).select(new Person() {
        {
            id = p.getId();
            firstName = p.getFirstName();
            lastName = p.getLastName();
            fullName = Function.concat(select, null, p.getFirstName(), " ", p.getLastName());
        }
    });
});

Here is another example:

@Entity
public class Account {

    @PrimaryKey
    private Long id;

    private Double credit;

    private Double rate;

    @Extension
    private Double interest;

    // Getters and setters omitted for brevity
}
Account a = sessionFactory.getFromSession(select -> {
    Account desc = new Account();
    select.from(desc).primaryKey().is(4L).selectFirst(new Account() {
        {
            id = desc.getId();
            credit = desc.getCredit();
            rate = id * credit;
        }
    });
});
  • @Generated: Marks fields that get their value via calling a sequence or identity type.
Attribute Type Description
GeneratorType enum Developers must specify the strategy using the value attribute:
  1. IDENTITY: Relies on database auto-increment columns.
  2. SEQUENCE: Uses a database sequence object to produce the ids. Use in conjunction with the 'seqName' attribute.
  3. UUID: EzQu will generate an id as a unique UUID. Needs a java field of a java.lang.String type with a varchar underlying column type or java.util.UUID with a Binary underlying column type. When table is generated by EzQu it is taken care of automatically.
  4. NONE: The default. This would mean the developer needs to handle the id outside of EzQu, and make sure it is unique.
seqName String when using sequence the name of the sequence to use

Caching, Mutability, and Indexing

Immutability effects two things.

  • @Immutable: The multiCallCache holds objects in cache between db calls within the same session. The multi cache makes fetching of data more efficient, because what was fetched before is held in cache and is not fetched again, also it makes sure that the same object instance is always fetched within the same session and thus, if a change is applied to that object during the session it will reflect in all other objects that hold a relation to it. i.e. if we fetch an entity 'A' that holds a relationship with entity 'C' and ina nother call in the same session we fetch entity 'B' wich also holds a relationship to the same 'C' we will get tge same 'C' instance.

    Sometimes this creates issues and ezQu will throw an exception stating it found two instances of the same entity in the session. While this is something that usually the developer should take care of, there are cases when this behavior should not be applied because the related entity is actually immutable and can not change, thus having different instances does not matter.
    @Immutable annotation should be put on such Entites to tell ezQu just that, and allow multi instances.
  • @NoUpdateOnSave: Instructs EzQu to skip updates for related objects in O2O relations, assuming they already exist.
  • @Index: This is a creational annotation, valid only if EzQu generates the table. It allows the creation of an index in the database
Attribute Type Description
unique boolean default false. set the index as unique index
name String a name to give the index
columns String[] the name of the columns to include in this index
  • @Indices: This is a creational annotation, valid only if EzQu generates the table. When creating more then one @Index.

Lifecycle Interceptors

  • @Interceptor: apply the annotation to an entity. The referenced class MUST implement CRUDInterceptor.
    • onInsert(K entity): Before DB insertion.
    • onMerge(K entity): Before a merge (insert-or-update) operation.
    • onUpdate(K entity): Before DB update.
    • onDelete(K entity): Before DB deletion.