The primary index for an entity class and its primary key.
PrimaryIndex objects are thread-safe. Multiple threads may
safely call the methods of a shared
PrimaryIndex object.
PrimaryIndex implements
EntityIndex to map the primary
key type (PK) to the entity type (E).
The
Entity annotation may be used to define an entity class and
the
PrimaryKey annotation may be used to define a primary key as
shown in the following example.
class Employee {
long id;
String name;
Employee(long id, String name) {
this.id = id;
this.name = name;
}
private Employee() {} // For bindings
}
To obtain the
PrimaryIndex for a given entity class, call
EntityStore.getPrimaryIndex EntityStore.getPrimaryIndex , passing the
primary key class and the entity class. For example:
EntityStore store = new EntityStore(...);
PrimaryIndex primaryIndex =
store.getPrimaryIndex(Long.class, Employee.class);
Note that
Long.class is passed as the primary key class, but the
primary key field has the primitive type
long . When a primitive
primary key field is used, the corresponding primitive wrapper class is used
to access the primary index. For more information on key field types, see
PrimaryKey .
The
PrimaryIndex provides the primary storage and access methods
for the instances of a particular entity class. Entities are inserted and
updated in the
PrimaryIndex by calling a method in the family of
PrimaryIndex.put methods. The
PrimaryIndex.put method will insert the entity if no
entity with the same primary key already exists. If an entity with the same
primary key does exist, it will update the entity and return the existing
(old) entity. For example:
Employee oldEntity;
oldEntity = primaryIndex.put(new Employee(1, "Jane Smith")); // Inserts an entity
assert oldEntity == null;
oldEntity = primaryIndex.put(new Employee(2, "Joan Smith")); // Inserts an entity
assert oldEntity == null;
oldEntity = primaryIndex.put(new Employee(2, "Joan M. Smith")); // Updates an entity
assert oldEntity != null;
The
PrimaryIndex.putNoReturn method can be used to avoid the overhead of
returning the existing entity, when the existing entity is not important to
the application. The return type of
PrimaryIndex.putNoReturn is void. For
example:
primaryIndex.putNoReturn(new Employee(1, "Jane Smith")); // Inserts an entity
primaryIndex.putNoReturn(new Employee(2, "Joan Smith")); // Inserts an entity
primaryIndex.putNoReturn(new Employee(2, "Joan M. Smith")); // Updates an entity
The
PrimaryIndex.putNoOverwrite method can be used to ensure that an existing
entity is not overwritten.
PrimaryIndex.putNoOverwrite returns true if the
entity was inserted, or false if an existing entity exists and no action was
taken. For example:
boolean inserted;
inserted = primaryIndex.putNoOverwrite(new Employee(1, "Jane Smith")); // Inserts an entity
assert inserted;
inserted = primaryIndex.putNoOverwrite(new Employee(2, "Joan Smith")); // Inserts an entity
assert inserted;
inserted = primaryIndex.putNoOverwrite(new Employee(2, "Joan M. Smith")); // No action was taken!
assert !inserted;
Primary key values must be unique, in other words, each instance of a
given entity class must have a distinct primary key value. Rather than
assigning the unique primary key values yourself, a sequence can be
used to assign sequential integer values automatically, starting with the
value 1 (one). A sequence is defined using the
PrimaryKey.sequence annotation property. For example:
class Employee {
long id;
String name;
Employee(String name) {
this.name = name;
}
private Employee() {} // For bindings
}
The name of the sequence used above is "ID". Any name can be used. If
the same sequence name is used in more than one entity class, the sequence
will be shared by those classes, in other words, a single sequence of
integers will be used for all instances of those classes. See
PrimaryKey.sequence for more information.
Any method in the family of
PrimaryIndex.put methods may be used to insert
entities where the primary key is assigned from a sequence. When the
PrimaryIndex.put method returns, the primary key field of the entity object will be set
to the assigned key value. For example:
Employee employee;
employee = new Employee("Jane Smith");
primaryIndex.putNoReturn(employee); // Inserts an entity
assert employee.id == 1;
employee = new Employee("Joan Smith");
primaryIndex.putNoReturn(employee); // Inserts an entity
assert employee.id == 2;
This begs the question: How do you update an existing entity, without
assigning a new primary key? The answer is that the
PrimaryIndex.put methods
will only assign a new key from the sequence if the primary key field is
zero or null (for reference types). If an entity with a non-zero and
non-null key field is passed to a
PrimaryIndex.put method, any existing entity
with that primary key value will be updated. For example:
Employee employee;
employee = new Employee("Jane Smith");
primaryIndex.putNoReturn(employee); // Inserts an entity
assert employee.id == 1;
employee = new Employee("Joan Smith");
primaryIndex.putNoReturn(employee); // Inserts an entity
assert employee.id == 2;
employee.name = "Joan M. Smith";
primaryIndex.putNoReturn(employee); // Updates an existing entity
assert employee.id == 2;
Since
PrimaryIndex implements the
EntityIndex interface,
it shares the common index methods for retrieving and deleting entities,
opening cursors and using transactions. See
EntityIndex for more
information on these topics.
Note that when using an index, keys and values are stored and retrieved
by value not by reference. In other words, if an entity object is stored
and then retrieved, or retrieved twice, each object will be a separate
instance. For example, in the code below the assertion will always
fail.
MyKey key = ...;
MyEntity entity1 = new MyEntity(key, ...);
index.put(entity1);
MyEntity entity2 = index.get(key);
assert entity1 == entity2; // always fails!
author: Mark Hayes |