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 for both sync and async API usage:

MultiDatabaseHiLoGenerator hiLoGenerator = new MultiDatabaseHiLoGenerator(32);
Conventions.DocumentKeyGenerator = (dbName, databaseCommands, entity) =>
					hiLoGenerator.GenerateDocumentKey(dbName, databaseCommands, Conventions, entity);

AsyncMultiDatabaseHiLoKeyGenerator asyncHiLoGenerator = new AsyncMultiDatabaseHiLoKeyGenerator(32);
Conventions.AsyncDocumentKeyGenerator = (dbName, commands, entity) =>
					asyncHiLoGenerator.GenerateDocumentKeyAsync(dbName, commands, 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.DocumentKeyGenerator = (dbname, commands, entity) =>
					store.Conventions.GetTypeTagName(entity.GetType()) + "/";

Function GetTypeTagName will use either the convention specified in FindTypeTagName (see below) or its default implementation.

FindTypeTagName and FindDynamicTagName

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. There are two functions that the client uses to determine the collection name. The first one is used for standard objects with well defined type:

Conventions.FindTypeTagName = type => // function that provides the collection name based on the entity type

The second one is dedicated for dynamic objects:

Conventions.FindDynamicTagName = dynamicObject => // function to determine the collection name for the given dynamic object

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.TransformTypeTagNameToDocumentKeyPrefix = tagName => // transform the tag name to the prefix of a key, e.g. [prefix]/12

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.

FindClrTypeName and FindClrType

In metadata of all documents stored in a database you can find the following property which specifies the client-side type. For instance:

{
    "Raven-Clr-Type": "Orders.Shipper, Northwind"
}

This property is used by RavenDB client to perform a conversion between .NET object and JSON document stored in a database. A function responsible for retrieving the CLR type of an entity is defined by FindClrTypeName convention:

Conventions.FindClrTypeName = type => // use reflection to determine the type;

To properly perform the revert conversion that is from a JSON result into a .NET object we need to retrieve the CLR type from Raven-Clr-Type metadata:

Conventions.FindClrType = (id, doc, metadata) =>
					metadata.Value<string>(Abstractions.Data.Constants.RavenClrType);

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.FindIdentityProperty = memberInfo => memberInfo.Name == "Id";

You can provide a customization based on the MemberInfo parameter to indicate which property or field keeps the identifier. The client will iterate over all object properties 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 .NET object a function that finds the identity property name for a given entity name is applied:

Conventions.FindIdentityPropertyNameFromEntityName = entityName => "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.IdentityPartsSeparator = "/";

IdentityTypeConvertors

RavenDB is designed to work with string identifiers. However it has the support for numeric and GUID ids. To be more exact it is able to work with Int32, Int64 and Guid identifiers, because it has dedicated converters for them:

Conventions.IdentityTypeConvertors = new List<ITypeConverter>
{
	new GuidConverter(),
	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 class UInt32Converter : ITypeConverter
{
	public bool CanConvertFrom(Type sourceType)
	{
		throw new CodeOmitted();
	}

	public string ConvertFrom(string tag, object value, bool allowNull)
	{
		throw new CodeOmitted();
	}

	public object ConvertTo(string value)
	{
		throw new CodeOmitted();
	}
}
Conventions.IdentityTypeConvertors.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.FindIdValuePartForValueTypeConversion = (entity, id) =>
	id.Split(new[] { Conventions.IdentityPartsSeparator }, StringSplitOptions.RemoveEmptyEntries).Last();

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.FindFullDocumentKeyFromNonStringIdentifier = (id, type, allowNull) => // by default returns [tagName]/[identityValue];

to find the full key based on the type of a document and the value type identifier.