All tables used by TJDO in a given schema are recorded in a single master table in that schema called JDO_TABLE. This table determines the mapping between Java classes/fields and tables for that schema. It has the following structure:
TABLE_ID | NEXT_ID | JAVA_NAME | TABLE_NAME |
---|---|---|---|
Primary key | Next hi-order value for OIDs | Fully-qualified Java class or field name | Table name |
JDO_TABLE constitutes the definitive list of tables managed by JDO. Any existing table not mentioned in JDO_TABLE is assumed to belong to a non-JDO application and is never touched.
Table names are generated from Java names with the following procedure:
TJDO includes an interface for performing a few manual operations directly on the JDO schema, such as adding tables for classes or clearing the schema. See SchemaManager.
With auto-table creation mode disabled, TJDO validates (see below) that all necessary database tables already exist and are correctly defined. With auto-table creation mode enabled, TJDO silently adds tables to the schema in the background as needed.
Auto-table creation mode can be enabled for a given PersistenceManagerFactory with:
((com.triactive.jdo.PersistenceManagerFactoryImpl)pmf).setAutoCreateTables(true);
or, alternatively, it can be enabled for all PersistenceManagerFactories by setting the system property:
com.triactive.jdo.AutoCreateTables=true
While it can be very convenient, auto-table creation mode is really intended for sandbox development and should remain disabled (the default) when running in production (if tables are missing in production, you have a bigger problem that you'd probably better not mask by auto-creating the missing tables).
The table(s) for a given class are created together with the tables for all other classes related to it. A failure to auto-create a given table often results in a whole group of related tables failing to be created. Also, see the FAQ list for a case where auto-table creation can sometimes fail unavoidably when using Oracle.
For the most part it is not possible to rename a TJDO table, and no API exists to do it. Even if a table is manually renamed, and its entry in JDO_TABLE modified accordingly, there are any number of columns, both in that table and others, whose names would have been generated based on the original table name (for example, the ID column of a class table is generated by appending "_ID" to the table name). If the table name changes, TJDO would expect any such columns to appear using the new name. A SchemaValidationException would occur unless every other column and foreign key that incorporates the old name is modified to use the new name. Whether this is even possible is left as an exercise for the intrepid.
With the exceptions of SchemaManager.dropTablesFor() and SchemaManager.dropAllTables(), TJDO never removes tables. It is possible to manually remove tables without disrupting TJDO if you also remove the corresponding entries from JDO_TABLE and restart any JVMs currently using the schema. However, in practice this is difficult to do because any table being removed must also have any other tables that reference it (via foreign keys) removed, and so on (this must be taken into consideration even when using dropTablesFor()).
As persistent objects are accessed, TJDO's internal StoreManager determines, using JDO_TABLE, which database table(s) are serving as backing for each class or field. Before a table is first accessed in a given JVM, the StoreManager always validates that its structure and keys are defined correctly according to the corresponding class and its JDO metadata. This prevents the software from failing, or the database from becoming corrupt, due to a mismatch between the two.
A failure of any validation step causes a SchemaValidationException to be thrown and the corresponding class fails to initialize, making it unusable for persistence. Any other unrelated classes that have passed validation remain usable. This allows portions of a system to proceed and work even if other portions are temporarily damaged.
Subsequent attempts to use a class that failed initialization will cause the StoreManager to repeat the initialization and schema validation procedure. If validation then succeeds, the class becomes usable. This allows schema errors to be corrected in the database, and the JDO subsystem to recover, without having to restart the JVM.
Tables are validated by confirming that:
Foreign keys are used wherever an ID column exists that recognizably refers to a specific table. An example of an ID column that would not refer to a specific table is a field declared as an interface type, or declared as a non-persistence-capable superclass having persistence-capable subclasses.
For those tables having foreign keys, their keys are validated by confirming that:
For validation purposes, a foreign key is defined as a list of FK columns, each with an associated PK column in some table. The name of a foreign key is unimportant, although TJDO will always generate names for new keys as tablename_FKn using the next available n.
If not automatically done by the database itself, TJDO will create indices for all columns used as a foreign key, unless a suitable index already exists. Primary keys are always assumed to have a backing index, whether reported by the database or not. An index is considered suitable if it equates to, or begins with, the column(s) that make up the foreign key. This only applies to foreign keys that are themselves managed by TJDO.
For those tables needing indices, the indices are validated by confirming that:
For validation purposes, an index is defined as simply a list of columns. The name of the index is unimportant, although TJDO will always generate names for new indices as tablename_Nn using the next available n.