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 and modifying constructors, methods and non persistent fields. However, additions, deletions and modifications to the persistent fields of an entity class are detected by ObjectDB. New entity objects have to be stored in the new class schema, and old entity objects, which were stored previously in the old class schema, have to 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 transparent use of old entity objects after schema change. When an entity object of an old schema is loaded into memory it is automatically converted into an instance of the up to date entity class. This is done automatically in memory each time the entity object is loaded. The database object is only updated to the new schema when that entity object is stored to the database again.

Conversion of an entity object to the new schema is done on a field by field basis:

  • For every field in the new schema for which there is a matching field in the old schema, the new field in the new entity object is initialized using the value of the matching old field in the original entity object.
  • 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 simply 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 might also be located in a different place in the class hierarchy. That makes automatic schema evolution very flexible and almost insensitive to class hierarchy changes (e.g. moving fields between classes in the hierarchy, removing an intermediate class in the hierarchy, etc.).

Convertible Types

When an old matching field is found but its type is different than the type of the new field (with the same name), a conversion is required. If the old type is inconvertible to the new type (for instance a change from int to Date) the fields are not considered as 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 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 type to any date type.
  • From any collection or array type to any collection or array type,
    as long as the elements are convertible (e.g. from int[] to ArrayList<Long>).
  • From any object to any collection or array that can contain that object as en element.
  • From any map type to any map type as long as the keys and values are convertible
    (e.g. 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 schema upgrade includes also renaming fields, classes or packages, these changes must be specified explicitly in the configuration to avoid data loss. The Schema Update section in chapter 6 explains how to specify such changes in the configuration file.