Using keys
Keys are defined as data type projections from a complex data type, i.e. keys refer to a subset of properties (attributes) of a complex data type. Usually, keys consist of a number of key components, which are related to attributes of the complex data type.
Key components can be marked as "case sensitive" and "descending". Both option will influence compare operations and order in indexes. When descending is set for a key component comparing keys will invert the result, i.e. the lower key value becomes the greater one. Since key compare functions are called also in order to create and update indexes, key component setting allow defining whether an index is ordered ascending or descending.
A specific key is the __IDENTITY key, which is implicitly defined as key for any persistent data type. __IDENTITY key values are available for independent instances, only, i.e. for instances stored as database entry in the database. __IDENTITY key values are not available for array elements of an array attribute.
Key values can be extracted from instances selected in a property handle. Keys can also be assigned to indexes (by name) in order to sort instances in a collection according to the key definition.
In order to use keys in programming, keys are passed as key strings (Key) in object interchange format (OIF). The Key class provides some features in order to create proper OIF strings for the key.
Keys are defined for complex data types. One of the defined keys can be assigned as primary key for the data type, i.e. the primary key depends on the data type. This is a conceptual approach indicating, that this is a common key for identifying instances in any collection. There is no consistency check, i.e. the system does not look for instances with duplicate keys in a global scope. In order to avoid duplicate keys, instances can be stored in a global extent that is ordered by the identifying key and required unique key values.
For weak-typed collections, where complex data types may differ for the selected instances, the primary key might differ as well. In order to get the proper primary key value for the selected instance is referred to as current key.
Any key defined for a complex data type can be used as access key (order key) for collections of instances of this data type. Defined access keys depend on the collection, i.e. children and parents may have got different access keys. In contrast to the primary key definition, the access key definition does not depend on the instance selected.
In case of unordered collections, the primary key (when being defined) is used as access key. Thus, the primary key can be used for locating an instance in an unordered collection.
When defining a unique unordered collection, instances have to be unique concerning the primary key, and, when no primary key has been defined, concerning to the instance LOID.
Keys are passed as a Key instance. The Key instance provides the key definition (typeDefinition()) and key data in different formats. The default format is the extended self delimiter fields format (ESDF), which separates key components by |, ; or tab.
Complex attributes used as key components (which can be avoided by explicitly defining each component attribute) are enclosed in {...}.
Thus, when using the default key format, those characters must both be part of key data. When you need to refer to keys containing those characters, you may pass keys in the more complex OIF or XML format after changing the key's string type (stringType()).
In order to convert the key into internal format, a typeDefinition is required for the key. The type definition is set automatically, when using the Key instance in a Property key access function. When passing key values to the function (e.g. for locating an instance), the application is responsible to provide the proper key value. In case of using ESDF key format, the sequence of the components is important. OIF is more difficult to write, but more save, since it assigns component values by attribute names.
Any key definition can be provided by key name
In order to check the key definition for the key to be used, one may read the type definition for the appropriate key by calling accessKeyDefinition(), primaryKeyDefinition() or currentKeyDefinition(). Then, you may call corresponding type definition functions in order toread key components (attributes) etc. from the type definition returned.
// constructing key instances
Key key("Miller|Paul"); // default key in ESDF format
Key k2;
k2.stringType(OIFString); // set OIF string type
k2 = "name = 'Miller'; first_name = 'Paul'"; // assign OIF data
// reading key definition
Property person(os,"Person::Persons");
TypeDefinition primaryKey(person.primaryKeyDefinition());
TypeDefinition accessKey(person.accessKeyDefinition());
Keys define an order by providing compare functions. Since the key definition allows inverting the sequence for single key components, the key order returned by the compare functions might be differ sometimes from what the user expects.
Considering a simple numeric key ordering a collection by an __AUTOIDENT (auto-numbering). In order to get newest instances on top of the collection, one might define descending order for this key. Now, comparing instances with key values 1 and 2 will return, that instance(1) is greater than instance(2).
Thus, the result returned from compareAccessKey() depends on the key definition, and not on values, only.