Global identifier generation conventions
DocumentKeyGenerator
You can setup a custom key generation strategy by supplying a custom function DocumentKeyGenerator
. By default a session uses the HiLo algorithm:
final MultiDatabaseHiLoGenerator hiLoGenerator = new MultiDatabaseHiLoGenerator(32);
conventions.setDocumentKeyGenerator(new DocumentKeyGenerator() {
@Override
public String generate(String dbName, IDatabaseCommands dbCommands, Object entity) {
return hiLoGenerator.generateDocumentKey(dbName, dbCommands, conventions, entity);
}
});
However if you want the session to use an identity key generation strategy by default, you can overwrite this convention in the following manner:
conventions.setDocumentKeyGenerator(new DocumentKeyGenerator() {
@Override
public String generate(String dbName, IDatabaseCommands dbCommands, Object entity) {
return store.getConventions().getTypeTagName(entity.getClass()) + "/";
}
});
Function getTypeTagName
will use either the convention specified in findTypeTagName
(see below) or its default implementation.
FindTypeTagName
Entity objects that share a common tag name belong to the same collection on the server side. Tag names are also used to build document keys.
conventions.setFindTypeTagName(new TypeTagNameFinder() {
@Override
public String find(Class<?> clazz) {
// function that provides the collection name based on the entity type
return clazz.getSimpleName();
}
});
TransformTypeTagNameToDocumentKeyPrefix
Actually, tag names determined by recently described convention functions aren't directly used as prefixes in document keys. There is a convention function called transformTypeTagNameToDocumentKeyPrefix
which takes the collection name and produces the prefix:
conventions.setTransformTypeTagNameToDocumentKeyPrefix(new TypeTagNameToDocumentKeyPrefixTransformer() {
@Override
public String transform(String tag) {
// transform the tag name to the prefix of a key, e.g. [prefix]/12
throw new CodeOmitted();
}
});
Its default behavior is that for a tag which contains one upper character it simply converts it to lower case string, e.g. Users
would be transformed into users
. For tag names containing more upper characters there will be no change, e.g. the tag name: LineItems
would output the following prefix: LineItems
.
FindJavaClassName and FindJavaClass
In metadata of all documents stored in a database you can find the following property which specifies the client-side type. For instance:
{
"Raven-Java-Class": "com.example.orders.Shipper"
}
This property is used by RavenDB client to perform a conversion between java object and JSON document stored in a database. A function responsible for retrieving the java class of an entity is defined by findJavaClassName
convention:
conventions.setFindJavaClassName(new JavaClassNameFinder() {
@Override
public String find(Class<?> clazz) {
// use reflection to determine the type;
return clazz.getSimpleName();
}
});
To properly perform the revert conversion that is from a JSON result into a java object we need to retrieve the java class from Raven-Java-Class
metadata:
conventions.setFindJavaClass(new JavaClassFinder() {
@Override
public String find(String id, RavenJObject doc, RavenJObject metadata) {
return metadata.value(String.class, Constants.RAVEN_JAVA_CLASS);
}
});
FindIdentityProperty
The client must know where in your entity an identifier is stored to be property able to transform it into JSON document. It uses findIdentityProperty
convention for that. The default and very common convention is that a property named Id
is the identifier, so it is the default one:
conventions.setFindIdentityProperty(new IdentityPropertyFinder() {
@SuppressWarnings("boxing")
@Override
public Boolean find(Field field) {
return "Id".equals(field.getName());
}
});
You can provide a customization based on the field
parameter to indicate which field keeps the identifier. The client will iterate over all object fields and take the first one according to the defined predicate.
FindIdentityPropertyNameFromEntityName
It can happen that sometimes the results returned by the server can haven't identifiers defined (for example if you run a projection query) however they have Raven-Entity-Name
in metadata.
Then to perform the conversion into java object a function that finds the identity property name for a given entity name is applied:
conventions.setFindIdentityPropertyNameFromEntityName(new IdentityPropertyNameFinder() {
@Override
public String find(String entityName) {
return "Id";
}
});
IdentityPartsSeparator
According to the default, convention document keys have the following format: [collectionName]/[identityValue]
. The slash character (/
) separates the two parts of an identifier.
You can overwrite it by using identityPartsSeparator
convention. Its default definition is:
conventions.setIdentityPartsSeparator("/");
IdentityTypeConvertors
RavenDB is designed to work with string identifiers. However it has the support for numeric and UUID ids. To be more exact it is able to work with int
, long
and UUID
identifiers,
because it has dedicated converters for them:
conventions.setIdentityTypeConvertors(Arrays.asList(
new UUIDConverter(),
new Int32Converter(),
new Int64Converter()
));
If you need to have the support for different types of identifier properties, you can add a custom converter that implements ITypeConverter
interface:
public static class UInt32Converter implements ITypeConverter {
@Override
public boolean canConvertFrom(Class<?> sourceType) {
throw new CodeOmitted();
}
@Override
public String convertFrom(String tag, Object value, boolean allowNull) {
throw new CodeOmitted();
}
@Override
public Object convertTo(String value) {
throw new CodeOmitted();
}
}
conventions.getIdentityTypeConvertors().add(new UInt32Converter());
FindIdValuePartForValueTypeConversion
You need to remember that even if the identity property of your entry isn't a string, a document in a database always has a string key. E.g. for the Orders
entity that has
a numeric ID and its value is 3
, the server side key will be orders/3
. If such document is fetched by RavenDB client, the key needs to be converted into a number. By default
we look for the last part of the identifier after identityPartsSeparator
:
conventions.setFindIdValuePartForValueTypeConversion(new IdValuePartFinder() {
@Override
public String find(Object entity, String id) {
return id.split(conventions.getIdentityPartsSeparator())[1];
}
});
FindFullDocumentKeyFromNonStringIdentifier
Sometimes the client needs to know the full id of the document that will be stored for an entity with non-sting identifier. We can use the following function:
conventions.setFindFullDocumentKeyFromNonStringIdentifier(new DocumentKeyFinder() {
@Override
public String find(Object id, Class<?> type, Boolean allowNull) {
// by default returns [tagName]/[identityValue];
throw new CodeOmitted();
}
});
to find the full key based on the type of a document and the value type identifier.