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.
This page covers the following topics:
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.Transient (JPA Annotation)Specifies that the property or field is not persistent. annotation (which only affects persistence):
@Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. 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.Transient (JPA Annotation)Specifies that the property or field is not persistent. 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.Transient (JPA Annotation)Specifies that the property or field is not persistent. 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:
- OneToOnejavax.persistence.OneToOne (JPA Annotation)Specifies a single-valued association to another entity that has one-to-one multiplicity., ManyToOnejavax.persistence.ManyToOne (JPA Annotation)Specifies a single-valued association to another entity class that has many-to-one multiplicity. - for references of entity types.
- OneToManyjavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity., ManyToManyjavax.persistence.ManyToMany (JPA Annotation)Specifies a many-valued association with many-to-many multiplicity. - for collections and maps of entity types.
- Basic javax.persistence.Basic (JPA Annotation)The simplest type of mapping to a database column.- for any other persistable type.
In JPA only Basicjavax.persistence.Basic (JPA Annotation)The simplest type of mapping to a database column. 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.Entity (JPA Annotation)Specifies that the class is an entity.public class EntityWithFieldSettings { @Basicjavax.persistence.Basic (JPA Annotation)The simplest type of mapping to a database column.(optionaljavax.persistence.Basic.optional (JPA Annotation Attribute)(Optional) Defines whether the value of the field or property may be null.=false) Integer field1; @OneToOnejavax.persistence.OneToOne (JPA Annotation)Specifies a single-valued association to another entity that has one-to-one multiplicity.(cascadejavax.persistence.OneToOne.cascade (JPA Annotation Attribute)(Optional) The operations that must be cascaded to the target of the association.=CascadeTypejavax.persistence.CascadeType (JPA Enum)Defines the set of cascadable operations that are propagated to the associated entity..ALLjavax.persistence.CascadeType.ALL (JPA Enum Constant)Cascade all operations) MyEntity field2; @OneToManyjavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity.(fetchjavax.persistence.OneToMany.fetch (JPA Annotation Attribute)(Optional) Whether the association should be lazily loaded or must be eagerly fetched.=FetchTypejavax.persistence.FetchType (JPA Enum)Defines strategies for fetching data from the database..EAGERjavax.persistence.FetchType.EAGER (JPA Enum Constant)Defines that data must be eagerly fetched.) 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.Embedded (JPA Annotation)Specifies a persistent field or property of an entity whose value is an instance of an embeddable class. annotation, requiring ObjectDB to verify that the type is indeed embeddable:
@Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. public class Person { @Embeddedjavax.persistence.Embedded (JPA Annotation)Specifies a persistent field or property of an entity whose value is an instance of an embeddable class. 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.Entity (JPA Annotation)Specifies that the class is an entity. public class Employee { String name; @ManyToOnejavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity. Department department; } @Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. public class Department { @OneToManyjavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity.(mappedByjavax.persistence.OneToMany.mappedBy (JPA Annotation Attribute)The field that owns the relationship.="department") Set<Employee> employees; }
The mappedByjavax.persistence.OneToMany.mappedBy (JPA Annotation Attribute)The field that owns the relationship. 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 mappedByjavax.persistence.OneToMany.mappedBy (JPA Annotation Attribute)The field that owns the relationship. 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.OrderBy (JPA Annotation)Specifies the ordering of the elements of a collection valued association or element collection at the point when the association or collection is retrieved. annotation:
@Entity public class Department { @OneToManyjavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity.(mappedByjavax.persistence.OneToMany.mappedBy (JPA Annotation Attribute)The field that owns the relationship.="department") @OrderByjavax.persistence.OrderBy (JPA Annotation)Specifies the ordering of the elements of a collection valued association or element collection at the point when the association or collection is retrieved.("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.MapKey (JPA Annotation)Specifies the map key for associations of type {@link java.util.Map 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. annotation:
@Entity public class Department { @OneToManyjavax.persistence.OneToMany (JPA Annotation)Specifies a many-valued association with one-to-many multiplicity.(mappedByjavax.persistence.OneToMany.mappedBy (JPA Annotation Attribute)The field that owns the relationship.="department") @MapKeyjavax.persistence.MapKey (JPA Annotation)Specifies the map key for associations of type {@link java.util.Map 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.(namejavax.persistence.MapKey.name (JPA Annotation Attribute)(Optional) The name of the persistent field or property of the associated entity that is used as the map key.="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.Entity (JPA Annotation)Specifies that the class is an entity. public class Employee { @OneToOnejavax.persistence.OneToOne (JPA Annotation)Specifies a single-valued association to another entity that has one-to-one multiplicity. MedicalInsurance medicalInsurance; } @Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. public class MedicalInsurance { @OneToOnejavax.persistence.OneToOne (JPA Annotation)Specifies a single-valued association to another entity that has one-to-one multiplicity.(mappedByjavax.persistence.OneToOne.mappedBy (JPA Annotation Attribute)(Optional) The field that owns the relationship.="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.Version (JPA Annotation)Specifies the version field or property of an entity class that serves as its optimistic lock value. annotation. In addition, a version field should have a numeric type:
@Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. public class EntityWithVersionField { @Versionjavax.persistence.Version (JPA Annotation)Specifies the version field or property of an entity class that serves as its optimistic lock value. 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.Access (JPA Annotation)Used 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. annotation on the class itself:
@Entityjavax.persistence.Entity (JPA Annotation)Specifies that the class is an entity. @Accessjavax.persistence.Access (JPA Annotation)Used 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.(AccessTypejavax.persistence.AccessType (JPA Enum)Used with the {@link 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..PROPERTYjavax.persistence.AccessType.PROPERTY (JPA Enum Constant)Property-based access is used.) public static class PropertyAccess { private int _id; @Idjavax.persistence.Id (JPA Annotation)Specifies the primary key of an entity. 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.