If you choose to use the session, you don't have to pay any special attention to the identifiers of the stored entities.
The session will take care of it by generating the identifiers automatically.
It utilizes conventions and HiLo algorithms to produce the identifiers.
Everything is handled by the session's mechanism and is transparent for the user.
However, you can influence the identifier generation strategy by overwriting
the identifier generation conventions.
In this article we are going to consider the behavior in accordance with the default conventions.
Identifiers in RavenDB are strings
Identifiers of documents in RavenDB database are always strings, so take this into consideration when you model your entities.
To figure out which property (or field) holds the entity's identifier, the convention
FindIdentityProperty is called.
By default, it looks for the property or the field named
Id (case sensitive). However, this property can
null value or even not be present at all. Then the automatic identifier generation strategy is performed.
The default convention is that entities get the identifiers in the following format
RavenDB client first determines the name of the collection that
the entity belongs to, then contacts the server to retrieve a numeric range of values. These values
can be used as the
The range of available numbers is calculated by using the
HiLo algorithm and is tracked per collection.
The current maximum value in ranges is stored in documents
Let's see the example.
var order = new Order
Id = null // value not provided
What will be the identifier of this order? You can check it by calling:
var orderId = session.Advanced.GetDocumentId(order); // "orders/1-A"
If this is the first
Order entity in your database, then it will return
orders/1-A. How does the identifier
generation process proceed? The RavenDB client determines the collection name as
(by default it is the plural form of the entity name).
Then it asks the server to give him the ID's range he can use (the first available range is 1 - 32). The server will
handle the Raven/Hilo/orders document.
The next available identifier value (always incrementing number) from the given range is
1 so its combination with
the collection name and the node tag gives the result
The next attempt to store another
Order object within the same session will result in creating the
identifier. However, this time asking the server about the possible range will not be necessary because the in-memory range
(1 - 32) is enough, so simply the next number will be added as the identifier suffix.
Identifier value numeric range generation
Each (in code) document store instance handles the generation of the identifier value numeric range. The database
stores the last requested number while the document store instances request ranges and caches the returned range of
The database has a single document (per collection) which stores the last identifier value requested by a document
E.g. the document
Raven/HiLo/accounts has the following value
then the next range will be
4001 - 4032, if 32 was range size (by default, it's 32).
The number of sessions per document store instance plays no part in identifiers value generation. When the store is
disposed of, the client sends the server the last value it used and the max value it got from the server.
Then the server will write it in the HiLo document (If the Max number is equal to the max number from the client
and bigger or equal to the last used value by the client)
If you intend to skip the identifier creation strategy that relies on the collection and HiLo value pair,
you can allow RavenDB to assign the Guid identifier to the stored document. Then, you have to provide the
string.Empty as the value of the
var orderEmptyId = new Order
Id = string.Empty // database will create a GUID value for it
var guidId = session.Advanced.GetDocumentId(orderEmptyId); // "bc151542-8fa7-45ac-bc04-509b343a8720"
This time the check for the document ID is called after
SaveChanges because only then we go to the server while
the entity's identifier is generated there.
Custom / Semantic IDs
The session also supports the option to store the entity and explicitly tell under what identifier it should be stored
in the database. To do this, you can either set the
Id property of the object:
var product = new Product
Id = "products/ravendb",
Name = "RavenDB"
or use the following
Store method overload:
Name = "RavenDB"
Server-side generated IDs
RavenDB also supports the notion of the identifier without the usage of the HiLo. By creating a string ID property
in your entity and setting it to a value ending with a slash (
/), you can ask RavenDB to assign a document ID to
a new document when it is saved.
Id = "companies/"
/ at the end of the ID will create an ID at the server-side by appending a numeric value and the node tag.
After executing the code above we will get from the server ID something that looks like
Be aware that the only guarantee for the numeric part is that it will always be increasing only within the same node.
If you need to have consecutive IDs across the cluster, you can use the identity option. To do so you need to use
a pipe (
|) as a suffix to the provided ID. It will tell RavenDB to create the ID when the document is saved but here it
will use a special always-incrementing integer value that is cluster-wide.
Id = "companies|"
After execution of the code above the ID will be
companies/1. Here we don't add the tag of the node to the end of
the ID because this number is unique in the cluster.
Identities are sequential, so running the above code again will generate
companies/2, and so on.
Using the pipe symbol (
|) as a prefix to the ID generates a call to the cluster and might affect performance
Note that we used
companies as the prefix just to follow the RavenDB convention. But nothing stands in your way to provide
a different prefix which will be completely unrelated to the collection name.
The identities are generated and updated on the server-side in atomic fashion. This means you can safely use this
approach in the concurrent writes scenario.