Database Schema Evolution

Modifications to entity classes that do not change their persistent field definitions (their schema) are transparent to ObjectDB. This includes adding, removing, or modifying constructors, methods, and non-persistent fields. However, ObjectDB detects additions, deletions, and modifications to the persistent fields of an entity class. New entities must be stored using the new class schema, and old entities, which were stored using the old class schema, must be converted to the new schema.

Note: In client-server mode, the ObjectDB server must be restarted after a schema change.

Automatic schema evolution

ObjectDB implements an automatic schema evolution mechanism that enables the transparent use of old entities after a schema change. When an entity with an old schema is loaded into memory, it is automatically converted to an instance of the up-to-date entity class. This conversion happens automatically in memory each time the entity is loaded. The object in the database is updated to the new schema only when that entity is stored in the database again.

An entity is converted to the new schema on a field-by-field basis:

  • For every field in the new schema that has a matching field in the old schema, the new field is initialized with the value of the matching old field.
  • Fields in the new schema that do not have matching fields in the old schema are initialized with default values (0, false, or null).
  • Fields in the old schema that do not have matching fields in the new schema are ignored, and their content is lost.

A matching field is a field with the same name and either the same type or a convertible type, as explained below. A matching field can also be located in a different place in the class hierarchy. This flexibility makes automatic schema evolution almost insensitive to class hierarchy changes, such as moving fields between class levels or removing an intermediate class from the hierarchy.

Convertible types

When a matching field is found but its type is different from the type of the new field, a conversion is required. If the old type cannot be converted to the new type (for example, a change from int to Date), the fields are not considered matching, and the new field is initialized with a default value (0, false, or null).

The following type conversions are supported:

  • From any numeric type to any other numeric type. In this context, numeric types are:
    byte, short, char, int, long, float, double, Byte, Short, Character, Integer, Long, Float, Double, BigInteger, BigDecimal, and enum values that are stored as numeric ordinal values (the default).
  • From any type to Boolean or boolean.
    (0, null, and false are converted to false; any other value is converted to true).
  • From any type to String (using toString() if necessary).
  • From String to numeric types, including enum types (when applicable).
  • From any date/time type to any other date/time type.
  • From any collection or array type to any other collection or array type,
    as long as the elements are convertible (for example, from int[] to ArrayList<Long>).
  • From any object to any collection or array that can contain that object as an element.
  • From any map type to any other map type, as long as the keys and values are convertible
    (for example, from HashMap<Long,Long> to TreeMap).
  • Any other conversion that is a valid casting operation in Java.

Renaming (package, class, and Field)

The automatic schema evolution mechanism, as described above, is based on matching fields by their names. When a schema upgrade also includes renaming fields, classes, or packages, you must specify these changes explicitly in the configuration to avoid data loss. The Schema Update section in Chapter 6 explains how to specify these changes in the configuration file.