Global Identifier Generation Conventions
FindCollectionName and FindCollectionNameForDynamic
Documents that have the same
@collection metadata belong to the same collection on the server side. Collection names are also used to build document identifiers. There are two functions that the client uses to determine a collection name for a given type. The first one is used for standard objects with a well-defined type:
FindCollectionName = type => // function that provides the collection name based on the entity type
The second one is dedicated for dynamic objects:
dynamicObject => // function to determine the collection name for the given dynamic object
What is a Dynamic Object?
FindCollectionNameForDynamic only works on objects that inherit from IDynamicMetaObjectProvider interface. In .NET there are two built-in types that implement that interface, the ExpandoObject and DynamicObject.
For example, if we want to determine a collection using a
Collection property from a dynamic object, we need to set
FindCollectionNameForDynamic as follows:
FindCollectionNameForDynamic = o => o.Collection
After that we can store our dynamic object as follows:
dynamic car = new ExpandoObject();
car.Name = "Ford";
car.Collection = "Cars";
dynamic animal = new ExpandoObject();
animal.Name = "Rhino";
animal.Collection = "Animals";
Collection names determined by recently described convention functions aren't directly used as prefixes in document identifiers. There is a convention function called
TransformTypeCollectionNameToDocumentIdPrefix which takes the collection name and produces the prefix:
collectionName => // transform the collection name to the prefix of a identifier, e.g. [prefix]/12
Its default behavior for a collection which contains one upper character is to simply convert it to lower case string.
Users would be transformed into
users. For collection names containing more upper characters, there will be no change. The collection name:
LineItems would output the following prefix:
FindClrTypeName and FindClrType
In the 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 a .NET object and a JSON document stored in a database. A function responsible for retrieving the CLR type of an entity is defined by
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 the
FindClrType = (id, doc) =>
if (doc.TryGet(Constants.Documents.Metadata.Key, out BlittableJsonReaderObject metadata) &&
metadata.TryGet(Constants.Documents.Metadata.RavenClrType, out string clrType))
The client must know where in your entity an identifier is stored to be properly able to transform it into JSON document. It uses the
FindIdentityProperty convention for that. The default and very common convention is that a property named
Id is the identifier, so is the default one:
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.
It can happen that sometimes the results returned by the server don't have identifiers defined (for example if you run a projection query). However, they have
@collection in metadata.
To perform the conversion into a .NET object, a function that finds the identity property name for a given entity name is applied:
FindIdentityPropertyNameFromCollectionName = collectionName => "Id"
According to the default, convention document identifiers have the following format:
[collectionName]/[identityValue]-[nodeTag]. The slash character (
/) separates the two parts of an identifier.
You can overwrite it by using
IdentityPartsSeparator convention. Its default definition is:
IdentityPartsSeparator = "/"