Session: Loading Entities



Load

The most basic way to load a single entity is to use one of the Load methods.

TResult Load<TResult>(string id);
Task<TResult> LoadAsync<TResult>(string id);
Parameter Type Description
id string Identifier of a document that will be loaded.
Return Type Description
TResult Instance of TResult or null if a document with a given ID does not exist.

Example

Employee employee = session.Load<Employee>("employees/1");
Employee employee = await asyncSession.LoadAsync<Employee>("employees/1");

Note

From RavenDB version 4.x onwards, only string identifiers are supported. If you are upgrading from 3.x, this is a major change, because in 3.x non-string identifiers are supported.

Load with Includes

When there is a 'relationship' between documents, those documents can be loaded in a single request call using the Include + Load methods. Learn more in How To Handle Document Relationships.

ILoaderWithInclude<object> Include(string path);

ILoaderWithInclude<T> Include<T>(Expression<Func<T, string>> path);

ILoaderWithInclude<T> Include<T>(Expression<Func<T, IEnumerable<string>>> path);

ILoaderWithInclude<T> Include<T, TInclude>(Expression<Func<T, string>> path);

ILoaderWithInclude<T> Include<T, TInclude>(Expression<Func<T, IEnumerable<string>>> path);
Parameter Type Description
path string or Expression Path in documents in which the server should look for 'referenced' documents.
Return Type Description
ILoaderWithInclude The Include method by itself does not materialize any requests but returns loader containing methods such as Load.

Example I

We can use this code to also load an employee which made the order.

// loading 'products/1'
// including document found in 'Supplier' property
Product product = session
    .Include("Supplier")
    .Load<Product>("products/1");

Supplier supplier = session.Load<Supplier>(product.Supplier); // this will not make server call
// loading 'products/1'
// including document found in 'Supplier' property
Product product = await asyncSession
    .Include("Supplier")
    .LoadAsync<Product>("products/1");

Supplier supplier = await asyncSession.LoadAsync<Supplier>(product.Supplier); // this will not make server call

Example II

// loading 'products/1'
// including document found in 'Supplier' property
Product product = session
    .Include<Product>(x => x.Supplier)
    .Load<Product>("products/1");

Supplier supplier = session.Load<Supplier>(product.Supplier); // this will not make server call
// loading 'products/1'
// including document found in 'Supplier' property
Product product = await asyncSession
    .Include<Product>(x => x.Supplier)
    .LoadAsync<Product>("products/1");

Supplier supplier = await asyncSession.LoadAsync<Supplier>(product.Supplier); // this will not make server call

Load - multiple entities

To load multiple entities at once, use one of the following Load overloads.

Dictionary<string, TResult> Load<TResult>(IEnumerable<string> ids);
Task<Dictionary<string, TResult>> LoadAsync<TResult>(IEnumerable<string> ids);
Parameter Type Description
ids IEnumerable<string> Multiple document identifiers to load
Return Type Description
Dictionary<string, TResult> Instance of Dictionary which maps document identifiers to TResult or null if a document with given ID doesn't exist.

Dictionary<string, Employee> employees = session.Load<Employee>(new[]
{
    "employees/1",
    "employees/2",
    "employees/3"
});
Dictionary<string, Employee> employees = await asyncSession.LoadAsync<Employee>(new[]
{
    "employees/1",
    "employees/2",
});

LoadStartingWith

To load multiple entities that contain a common prefix, use the LoadStartingWith method from the Advanced session operations.

T[] LoadStartingWith<T>(
    string idPrefix,
    string matches = null,
    int start = 0,
    int pageSize = 25,
    string exclude = null,
    string startAfter = null);

void LoadStartingWithIntoStream(
    string idPrefix,
    Stream output,
    string matches = null,
    int start = 0,
    int pageSize = 25,
    string exclude = null,
    string startAfter = null);
Task<T[]> LoadStartingWithAsync<T>(
    string idPrefix,
    string matches = null,
    int start = 0,
    int pageSize = 25,
    string exclude = null,
    string startAfter = null);

Task LoadStartingWithIntoStreamAsync(
    string idPrefix,
    Stream output,
    string matches = null,
    int start = 0,
    int pageSize = 25,
    string exclude = null,
    string startAfter = null);
Parameter Type Description
idPrefix string prefix for which the documents should be returned
matches string pipe ('|') separated values for which document IDs (after 'idPrefix') should be matched ('?' any single character, '*' any characters)
start int number of documents that should be skipped
pageSize int maximum number of documents that will be retrieved
exclude string pipe ('|') separated values for which document IDs (after 'idPrefix') should not be matched ('?' any single character, '*' any characters)
skipAfter string skip document fetching until given ID is found and return documents after that ID (default: null)
Return Type Description
TResult[] Array of entities matching given parameters.
Stream Output entities matching given parameters as a stream.

Example I

// return up to 128 entities with Id that starts with 'employees'
Employee[] result = session
    .Advanced
    .LoadStartingWith<Employee>("employees", null, 0, 128);
// return up to 128 entities with Id that starts with 'employees'
Employee[] result = (await asyncSession
    .Advanced
    .LoadStartingWithAsync<Employee>("employees", null, 0, 128))
    .ToArray();

Example II

// return up to 128 entities with Id that starts with 'employees/' 
// and rest of the key begins with "1" or "2" e.g. employees/10, employees/25
Employee[] result = session
    .Advanced
    .LoadStartingWith<Employee>("employees/", "1*|2*", 0, 128);
// return up to 128 entities with Id that starts with 'employees/' 
// and rest of the key begins with "1" or "2" e.g. employees/10, employees/25
Employee[] result = (await asyncSession
    .Advanced
    .LoadStartingWithAsync<Employee>("employees/", "1*|2*", 0, 128))
    .ToArray();

ConditionalLoad

This method can be used to check whether a document has been modified since the last time its change vector was recorded, so that the cost of loading it can be saved if it has not been modified.

The ConditionalLoad method takes a document's change vector. If the entity is tracked by the session, this method returns the entity. If the entity is not tracked, it checks if the provided change vector matches the document's current change vector on the server side. If they match, the entity is not loaded. If the change vectors do not match, the document is loaded.

The method is accessible from the session.Advanced operations.

(T Entity, string ChangeVector) ConditionalLoad<T>(string id, string changeVector);
Task<(T Entity, string ChangeVector)> ConditionalLoadAsync<T>(string id, string changeVector);
Parameter Type Description
id string The identifier of a document to be loaded.
changeVector string The change vector you want to compare with the server-side change vector. If the change vectors match, the document is not loaded.
Return Type Description
ValueTuple (T Entity, string ChangeVector) If the given change vector and the server side change vector do not match, the method returns the requested entity and its current change vector.
If the change vectors match, the method returns default as the entity, and the current change vector.
If the specified document, the method returns only default without a change vector.

Example

string changeVector;
User user = new User { Name = "Bob" };

using (var session = store.OpenSession())
{
    session.Store(user, "users/1");
    session.SaveChanges();

    changeVector = session.Advanced.GetChangeVectorFor(user);
}

// New session which does not track our User entity
using (var session = store.OpenSession())
{
    // The given change vector matches 
    // the server-side change vector
    // Does not load the document
    var result1 = session.Advanced
                   .ConditionalLoad<User>("users/1", changeVector);

    // Modify the document
    user.Name = "Bob Smith";
    session.Store(user);
    session.SaveChanges();

    // Change vectors do not match
    // Loads the document
    var result2 = session.Advanced
                   .ConditionalLoad<User>("users/1", changeVector);
}
string changeVector;
User user = new User { Name = "Bob" };

using (var session = store.OpenAsyncSession())
{
    await session.StoreAsync(user, "users/1");
    await session.SaveChangesAsync();

    changeVector = session.Advanced.GetChangeVectorFor(user);
}

// New session which does not track our User entity
using (var session = store.OpenAsyncSession())
{
    // The given change vector matches 
    // the server-side change vector
    // Does not load the document
    var result1 = await session.Advanced
                   .ConditionalLoadAsync<User>("users/1", changeVector);

    // Modify the document
    user.Name = "Bob Smith";
    await session.StoreAsync(user);
    await session.SaveChangesAsync();

    // Change vectors do not match
    // Loads the document
    var result2 = await session.Advanced
                   .ConditionalLoadAsync<User>("users/1", changeVector);
}

Stream

Entities can be streamed from the server using one of the following Stream methods from the Advanced session operations.

Streaming query results does not support the include feature. Learn more in How to Stream Query Results.

Information

Entities loaded using Stream will be transient (not attached to session).

IEnumerator<StreamResult<T>> Stream<T>(IQueryable<T> query);

IEnumerator<StreamResult<T>> Stream<T>(IQueryable<T> query, out StreamQueryStatistics streamQueryStats);

IEnumerator<StreamResult<T>> Stream<T>(IDocumentQuery<T> query);

IEnumerator<StreamResult<T>> Stream<T>(IRawDocumentQuery<T> query);

IEnumerator<StreamResult<T>> Stream<T>(IRawDocumentQuery<T> query, out StreamQueryStatistics streamQueryStats);

IEnumerator<StreamResult<T>> Stream<T>(IDocumentQuery<T> query, out StreamQueryStatistics streamQueryStats);

IEnumerator<StreamResult<T>> Stream<T>(string startsWith, string matches = null, int start = 0, int pageSize = int.MaxValue, string startAfter = null);
Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IQueryable<T> query);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IQueryable<T> query, out StreamQueryStatistics streamQueryStats);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IDocumentQuery<T> query);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IRawDocumentQuery<T> query);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IRawDocumentQuery<T> query, out StreamQueryStatistics streamQueryStats);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IDocumentQuery<T> query, out StreamQueryStatistics streamQueryStats);

Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(string startsWith, string matches = null, int start = 0, int pageSize = int.MaxValue, string startAfter = null);
Parameter Type Description
startsWith string prefix for which documents should be streamed
matches string pipe ('|') separated values for which document IDs should be matched ('?' any single character, '*' any characters)
start int number of documents that should be skipped
pageSize int maximum number of documents that will be retrieved
skipAfter string skip document fetching until a given ID is found and returns documents after that ID (default: null)
StreamQueryStats streamQueryStats (out parameter) Information about the streaming query (amount of results, which index was queried, etc.)
Return Type Description
IEnumerator<StreamResult> Enumerator with entities.
streamQueryStats (out parameter) Information about the streaming query (amount of results, which index was queried, etc.)

Example I

Stream documents for a ID prefix:

IEnumerator<StreamResult<Employee>> enumerator = session
    .Advanced
    .Stream<Employee>("employees/");

while (enumerator.MoveNext())
{
    StreamResult<Employee> employee = enumerator.Current;
}
IAsyncEnumerator<StreamResult<Employee>> enumerator = await asyncSession
    .Advanced
    .StreamAsync<Employee>("employees/");

while (await enumerator.MoveNextAsync())
{
    StreamResult<Employee> employee = enumerator.Current;
}

Example 2

Fetch documents for a ID prefix directly into a stream:

using (var outputStream = new MemoryStream())
{
    session
        .Advanced
        .LoadStartingWithIntoStream("employees/", outputStream);
}
using (var outputStream = new MemoryStream())
{
    await asyncSession
        .Advanced
        .LoadStartingWithIntoStreamAsync("employees/", outputStream);
}

IsLoaded

Use the IsLoaded method from the Advanced session operations To check if an entity is attached to a session (e.g. because it's been previously loaded).

IsLoaded checks if an attempt to load a document has been already made during the current session, and returns true even if such an attemp was made and failed.
If, for example, the Load method was used to load employees/3 during this session and failed because the document has been previously deleted, IsLoaded will still return true for employees/3 for the remainder of the session just because of the attempt to load it.

bool IsLoaded(string id);
Parameter Type Description
id string Entity ID for which the check should be performed.
Return Type Description
bool Indicates if an entity with a given ID is loaded.

Example

bool isLoaded = session.Advanced.IsLoaded("employees/1"); // false
Employee employee = session.Load<Employee>("employees/1");
isLoaded = session.Advanced.IsLoaded("employees/1"); // true
bool isLoaded = asyncSession.Advanced.IsLoaded("employees/1"); // false
Employee employee = await asyncSession.LoadAsync<Employee>("employees/1");
isLoaded = asyncSession.Advanced.IsLoaded("employees/1"); // true