ObjectDB ObjectDB

JPA Entity Fields

Fields of persistable user defined classes (entity classes, embeddable classes and mapped superclasses) can be classified into the following five groups:

  • Transient fields
  • Persistent fields
  • Inverse (Mapped By) fields
  • Primary key (ID) fields
  • Version field

The first three groups (transient, persistent and inverse fields) can be used in both entity classes and embeddable classes. However, the last two groups (primary key and version fields) can only be used in entity classes.

Primary key fields are discussed in the Primary Key section.

Transient Fields

Transient entity fields are fields that do not participate in persistence and their values are never stored in the database (similar to transient fields in Java that do not participate in serialization). Static and final entity fields are always considered to be transient. Other fields can be declared explicitly as transient using either the Java transient modifier (which also affects serialization) or the JPA @Transientjavax.persistence.TransientJPA annotationSpecifies that the property or field is not persistent.See JavaDoc Reference Page... annotation (which only affects persistence):

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class EntityWithTransientFields {
    static int transient1; // not persistent because of static
    final int transient2 = 0; // not persistent because of final
    transient int transient3; // not persistent because of transient
    @Transientjavax.persistence.TransientJPA annotationSpecifies that the property or field is not persistent.See JavaDoc Reference Page... int transient4; // not persistent because of @Transient
}

The above entity class contains only transient (non persistent) entity fields with no real content to be stored in the database.

Persistent Fields

Every non-static non-final entity field is persistent by default unless explicitly specified otherwise (e.g. by using the @Transientjavax.persistence.TransientJPA annotationSpecifies that the property or field is not persistent.See JavaDoc Reference Page... annotation).

Storing an entity object in the database does not store methods or code. Only the persistent state of the entity object, as reflected by its persistent fields (including persistent fields that are inherited from ancestor classes), is stored.

When an entity object is stored in the database every persistent field must contain either null or a value of one of the supported persistable types. ObjectDB supports persistent fields with any declared static type, including a generic java.lang.Object, as long as the type of the actual value at runtime is persistable (or null).

Every persistent field can be marked with one of the following annotations:

In JPA only Basicjavax.persistence.BasicJPA annotationThe simplest type of mapping to a database column.See JavaDoc Reference Page... is optional while the other annotations above are required when applicable. ObjectDB, however, does not enforce using any of these annotations, so they are useful only for classes that are also in use with an ORM JPA provider (such as Hibernate) or to change default field settings. For example:

@Entity
javax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...public class EntityWithFieldSettings {
    @Basicjavax.persistence.BasicJPA annotationThe simplest type of mapping to a database column.See JavaDoc Reference Page...(optionalBasic.optionalannotation element(Optional) Defines whether the value of the field or property may be null.See JavaDoc Reference Page...=false) Integer field1;
    @OneToOnejavax.persistence.OneToOneJPA annotationDefines a single-valued association to another entity that has
 one-to-one multiplicity.See JavaDoc Reference Page...(cascadeOneToOne.cascadeannotation element(Optional) The operations that must be cascaded to 
 the target of the association.See JavaDoc Reference Page...=CascadeTypejavax.persistence.CascadeTypeJPA enumDefines the set of cascadable operations that are propagated 
 to the associated entity.See JavaDoc Reference Page....ALLCascadeType.ALLenum constantCascade all operationsSee JavaDoc Reference Page...) MyEntity field2;
    @OneToManyjavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page...(fetchOneToMany.fetchannotation element(Optional) Whether the association should be lazily loaded or
 must be eagerly fetched.See JavaDoc Reference Page...=FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....EAGERFetchType.EAGERenum constantDefines that data must be eagerly fetched.See JavaDoc Reference Page...) List<MyEntity> field3;
}

The entity class declaration above demonstrates using field and relationship annotations to change the default behavior. null values are allowed by default. Specifying optional=false (as demonstrated for field1) causes an exception to be thrown on any attempt to store an entity with a null value in that field. Cascade and fetch settings are explained in chapter 3.

A persistent field whose type is embeddable may optionally be marked with the @Embeddedjavax.persistence.EmbeddedJPA annotationSpecifies a persistent field or property of an entity whose value is an instance of an embeddable class.See JavaDoc Reference Page... annotation, requiring ObjectDB to verify that the type is indeed embeddable:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class Person {
    @Embeddedjavax.persistence.EmbeddedJPA annotationSpecifies a persistent field or property of an entity whose 
 value is an instance of an embeddable class.See JavaDoc Reference Page... Address address;
}

Inverse Fields

Inverse (or mapped by) fields contain data that is not stored as part of the entity in the database, but is still available after retrieval by a special automatic query.

Note: Navigation through inverse fields is much less efficient than navigation through ordinary persistent fields, since it requires running queries. Inverse fields are essential for collection fields when using ORM JPA implementations, but not when using ObjectDB. Avoiding bidirectional relationships and inverse fields, and maintaining two unidirectional relationships is usually much more efficient (unless navigation in the inverse direction is rare).

The following entity classes demonstrate a bidirectional relationship:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class Employee {
    String name;
    @ManyToOnejavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page... Department department;
}

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class Department {
    @OneToManyjavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page...(mappedByOneToMany.mappedByannotation elementThe field that owns the relationship.See JavaDoc Reference Page...="department") Set<Employee> employees;
}

The mappedByOneToMany.mappedByannotation elementThe field that owns the relationship.See JavaDoc Reference Page... element (above) specifies that the employees field is an inverse field rather than a persistent field. The content of the employees set is not stored as part of a Department entity. Instead, employees is automatically populated when a Department entity is retrieved from the database. ObjectDB accomplishes this by effectively running the following query (where :d represents the Department entity):

SELECT e FROM Employee e WHERE e.department = :d

The mappedByOneToMany.mappedByannotation elementThe field that owns the relationship.See JavaDoc Reference Page... element defines a bidirectional relationship. In a bidirectional relationship, the side that stores the data (the Employee class in our example) is the owner. Only changes to the owner side affect the database, since the other side is not stored and calculated by a query.

An index on the owner field may accelerate the inverse query and the load of the inverse field. But even with an index, executing a query for loading a field is relatively slow. Therefore, if the employees field is used often, a persistent field rather than an inverse field is expected to be more efficient. In this case, two unidirectional and unrelated relationships are managed by the Employee and the Department classes, and the application is responsible to keep them synchronized.

Inverse fields may improve efficiency when managing very large collections that are changed often. This is because a change in the inverse field does not require storing the entire collection again. Only the owner side is stored in the database.

Special settings are available for inverse fields whose type is List or Map. For an inverse list field, the order of the retrieved owner entities can be set by the OrderByjavax.persistence.OrderByJPA annotationSpecifies the ordering of the elements of a collection valued association or element collection at the point when the association or collection is retrieved.See JavaDoc Reference Page... annotation:


@Entity
public class Department {
    @OneToManyjavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page...(mappedByOneToMany.mappedByannotation elementThe field that owns the relationship.See JavaDoc Reference Page...="department") @OrderByjavax.persistence.OrderByJPA annotationSpecifies the ordering of the elements of a collection valued
 association or element collection at the point when the association
 or collection is retrieved.See JavaDoc Reference Page...("name")
    List<Employee> employees;
}

In that case the employees field is filled with the results of the following query:

SELECT e FROM Employee e WHERE e.department = :d ORDER BY e.name

The specified field ("name") must be a sortable field of the owner side.

For an inverse map field, the keys can be extracted from the inverse query results by specifying a selected key field using the MapKeyjavax.persistence.MapKeyJPA annotationSpecifies the map key for associations of type java.util.Map when the map key is itself the primary key or a persistent field or property of the entity that is the value of the map.See JavaDoc Reference Page... annotation:


@Entity
public class Department {
    @OneToManyjavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page...(mappedByOneToMany.mappedByannotation elementThe field that owns the relationship.See JavaDoc Reference Page...="department") @MapKeyjavax.persistence.MapKeyJPA annotationSpecifies the map key for associations of type 
 java.util.Map when the map key is itself the primary
 key or a persistent field or property of the entity that is
 the value of the map.See JavaDoc Reference Page...(nameMapKey.nameannotation element(Optional) The name of the persistent field or property of the 
 associated entity that is used as the map key.See JavaDoc Reference Page...="name")
    Map<String,Employee> employees;
}

The employees map is filled with a mapping of employee names to the Employee objects to which they pertain.

Single value inverse fields are also supported:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class Employee {
    @OneToOnejavax.persistence.OneToOneJPA annotationDefines a single-valued association to another entity that has
 one-to-one multiplicity.See JavaDoc Reference Page... MedicalInsurance medicalInsurance;
}

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class MedicalInsurance {
    @OneToOnejavax.persistence.OneToOneJPA annotationDefines a single-valued association to another entity that has
 one-to-one multiplicity.See JavaDoc Reference Page...(mappedByOneToOne.mappedByannotation element(Optional) The field that owns the relationship.See JavaDoc Reference Page...="medicalInsurance") Employee employee;
}

A single value inverse field is less efficient than an inverse collection or map field because no proxy class is used and the inverse query is executed eagerly when the entity object is first accessed.

Version Field

ObjectDB maintains a version number for every entity object. The initial version of a new entity object (when stored in the database for the first time) is 1. For every transaction in which an entity object is modified its version number is automatically increased by one. Version fields are used in conjunction with optimistic locking (as explained in the Locking in JPA section in chapter 3).

You can expose entity object versions and make their values accessible to your application by marking the version fields in your entity classes with the Versionjavax.persistence.VersionJPA annotationSpecifies the version field or property of an entity class that serves as its optimistic lock value.See JavaDoc Reference Page... annotation. In addition, a version field should have a numeric type:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page... public class EntityWithVersionField {
     @Versionjavax.persistence.VersionJPA annotationSpecifies the version field or property of an entity class that
 serves as its optimistic lock value.See JavaDoc Reference Page... long version;
}

If a version field exists, ObjectDB automatically injects the version value into that field. Version fields should be treated as read only by the application and no mutator methods should be written against them. Only one version field per entity class is allowed. In fact, a single version field per entity class hierarchy is sufficient because a version field is inherited by subclasses.

Unlike ORM JPA providers, ObjectDB always manages versions for entity objects, regardless of whether or not a version field is explicitly defined. Therefore, optimistic locking is supported by ObjectDB even when a version field is not defined. Nevertheless, defining a version field has some advantages:

  • The application becomes more portable (to ORM-based JPA implementations).
  • Even when entity object versions are not in use directly by the application, exposing their values might be useful occasionally for debugging and logging.
  • Version values cannot be preserved for detached entity objects (explained in chapter 3) unless either the entity class is enhanced (explained in chapter 5) or a version field is explicitly defined.

Property Access

When an entity is being stored in the database data is extracted from the persistent fields of that entity. Likewise, when an entity is retrieved the persistent fields are initialized with data from the database.

By default, ObjectDB accesses the fields directly, but accessing fields indirectly as properties using get and set methods is also supported. To use property access mode, every non-transient field must have get and set methods based on the Java bean property convention.

Property access is enabled by moving all the JPA annotations from the fields to their respective get methods and specifying the Accessjavax.persistence.AccessJPA annotationUsed to specify an access type to be applied to an entity class, mapped superclass, or embeddable class, or to a specific attribute of such a class.See JavaDoc Reference Page... annotation on the class itself:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page... @Accessjavax.persistence.AccessJPA annotationUsed to specify an access type to be applied to an entity class,
 mapped superclass, or embeddable class, or to a specific attribute
 of such a class.See JavaDoc Reference Page...(AccessTypejavax.persistence.AccessTypeJPA enumIs used with the Access annotation to specify an access
 type to be applied to an entity class, mapped superclass, or
 embeddable class, or to a specific attribute of such a class.See JavaDoc Reference Page....PROPERTYAccessType.PROPERTYenum constantProperty-based access is used.See JavaDoc Reference Page...)
public static class PropertyAccess {
    private int _id;
    @Idjavax.persistence.IdJPA annotationSpecifies the primary key of an entity.See JavaDoc Reference Page... int getId() { return _id; }
    void setId(int id) { _id = id; }

    private String str;
    String getStr() { return str; }
    void setStr(String str) { this.str = str; }
}

In some JPA implementations, such as Hibernate, using property access may have some performance benefits. This is not the case with ObjectDB. Therefore, considering the extra complexity that is involved in setting up and maintaining property access, the default field access mode is usually preferred.