A datastore often provides ways of constraining the storage of data to maintain relationships and improve
performance. These are known as
constraints
and they come in various forms. These are :-
-
Indexes - these are used to mark fields that are referenced often as indexes so that
when they are used the performance is optimised.
-
Unique constraints - these are placed on fields that should have a unique value.
That is only one object will have a particular value.
-
Foreign-Keys - these are used to interrelate objects, and allow the datastore to keep
the integrity of the data in the datastore.
-
Primary-Keys - allow the PK to be set, and also to have a name.
The majority of datastores provide the ability to have indexes defined to give performance benefits.
With RDBMS the indexes are specified on the table and the indexes to the rows are stored separately.
In the same way an ODBMS typically allows indexes to be specified on the fields of the class, and these
are managed by the datastore. JDO 2 provides a mechanism for defining indexes, and hence if a developer
knows that a particular field is going to be highly used for querying, they can select that field to be
indexed in their (JDO) persistence solution.
Let's take an example class, and show how to specify this
public class Booking
{
private int bookingType;
...
}
We decide that our
bookingType
is going to be highly used and we want to index this in the
persistence tool. To do this we define the Meta-Data for our class as
<class name="Booking">
<field name="bookingType">
<index name="BOOKING_TYPE_INDEX"/>
</field>
</class>
This will mean that DataNucleus will create an index in the datastore for the field and the index will have the
name
BOOKING_TYPE_INDEX
(for datastores that support using named indexes).
If we had wanted the index to provide uniqueness, we could have made this
<index name="BOOKING_TYPE_INDEX" unique="true"/>
This has demonstrated indexing the fields of a class. The above example will index together all columns
for that field. In certain circumstances you want to be able to index from the column point of view.
So we are thinking more from a database perspective. Here we define our indexes at the <class>
level, like this
<class name="Booking">
<index name="MY_BOOKING_INDEX">
<column name="BOOKING"/>
</index>
...
</class>
This creates an index for the specified column (where the datastore supports columns i.e RDBMS).
See also :-
Relational Databases (RDBMS) provide the ability to have unique constraints defined on tables to give
extra control over data integrity. JDO 2 provides a mechanism for defining such unique constraints.
Lets take the previous class, and show how to specify this
<class name="Booking">
<field name="bookingType">
<unique name="BOOKING_TYPE_CONSTRAINT"/>
</field>
</class>
So in an identical way to the specification of an index. This example specification will result in the
column(s) for "bookingType" being enforced as unique in the datastore. In the same way you can specify
unique constraints directly to columns - see the example above for indexes.
Again, as for index, you can also specify unique constraints at "class" level in the MetaData file.
This is useful to specify where the composite of 2 or more columns or fields are unique. So with this
example
<class name="Booking">
<unique name="UNIQUE_PERF">
<field name="performanceDate"/>
<field name="startTime"/>
</unique>
<field name="performanceDate"/>
<field name="startTime"/>
</class>
The table for Booking has a unique constraint on the columns for the fields
performanceDate
and
startTime
See also :-
When objects have relationships with one object containing, for example, a Collection of another object,
it is common to store a foreign key in the datastore representation to link the two associated tables.
Moreover, it is common to define behaviour about what happens to the dependent object when the owning
object is deleted. Should the deletion of the owner cause the deletion of the dependent object maybe ?
Lets take an example
public class Hotel
{
private Set rooms;
...
}
public class Room
{
private int numberOfBeds;
...
}
We now want to control the relationship so that it is linked by a named foreign key, and that
we cascade delete the
Room
object when we delete the
Hotel
. We define the
Meta-Data like this
<class name="Hotel">
<field name="rooms">
<collection element-type="com.mydomain.samples.hotel.Room"/>
<foreign-key name="HOTEL_ROOMS_FK" delete-action="cascade"/>
</field>
</class>
So we now have given the datastore control over the cascade deletion strategy for objects stored
in these tables. Please be aware that JDO2 provides
Dependent Fields as a way of allowing cascade
deletion. The difference here is that
Dependent Fields
is controlled by DataNucleus,
whereas foreign key delete actions are controlled by the datastore (assuming the datastore
supports it even)
DataNucleus provides an extension that can give significant benefit to users. This is provided via the
PersistenceManagerFactory
datanucleus.rdbms.constraintCreateMode
. This property has 2 values.
The default is
DataNucleus
which will automatically decide which foreign keys are required to satisfy
the relationships that have been specified, whilst utilising the information provided in the MetaData
for foreign keys. The other option is
JDO2
which will simply create foreign keys that have been
specified in the MetaData file(s).
Note that the
foreign-key
for a 1-N FK relation can be specified as above, or under the
element
element. Note that the
foreign-key
for a 1-N JoinTable relation is specified
under
field
for the FK from owner to join table, and is specified under
element
for the FK
from join table to element table.
See also :-
In RDBMS datastores, it is accepted as good practice to have a primary key on all tables. You specify
in other parts of the MetaData which fields are part of the primary key (if using applicatioin identity),
or you define the name of the column DataNucleus should use for the primary key (if using datastore identity).
What these other parts of the MetaData don't allow is specifying the constraint name for the primary key.
You can specify this if you wish, like this
<class name="Booking">
<primary-key name="BOOKING_PK"/>
...
</class>
When the schema is generated for this table, the primary key will be given the specified name, and will
use the column(s) specified by the identity type in use.
In the case where you have a 1-N/M-N relation using a join table you can specify the name of the primary
key constraint used as follows
<class name="Hotel">
<field name="rooms">
<collection element-type="com.mydomain.samples.hotel.Room"/>
<join>
<primary-key name="HOTEL_ROOM_PK"/>
</join>
</field>
</class>
This creates a PK constraint with name "HOTEL_ROOM_PK".
See also :-