Session: Loading Entities

There are various methods with many overloads that allow a user to download documents from a database and convert them to entities. This article will cover the following methods:

Load

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

T Load<T>(string id);

T Load<T>(ValueType id);

TResult Load<TResult>(
	string id,
	string transformer,
	Action<ILoadConfiguration> configure);

TResult Load<TResult>(
	string id,
	Type transformerType,
	Action<ILoadConfiguration> configure = null);

TResult Load<TTransformer, TResult>(
	string id,
	Action<ILoadConfiguration> configure = null)
	where TTransformer : AbstractTransformerCreationTask, new();
Parameters
id string or ValueType Identifier of a document that will be loaded.
transformer or transformerType string or Type Name or type of a transformer to use on a loaded document.
configure Action Additional configuration that should be used during an operation e.g. transformer parameters can be added.
Return Value
TResult Instance of TResult or null if a document with a given ID does not exist.

Example I

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

Example II

// loading 'employees/1'
// and transforming result using 'Employees_NoLastName' transformer
// which returns 'LastName' as 'null'
Employee employee = session.Load<Employees_NoLastName, Employee>("employees/1");

Non String Identifiers

The above examples show how to load a document by its string key.

What if a type of your entity's identifier is not a string? You need to use an overload of the Load method that takes a parameter which type is ValueType.

Example III

If you have an entity where an identifier is an integer number:

public class EntityWithIntegerId
		{
c int Id { get; set; }
			/*
			...
			*/
		}

You can load it by specifying an integer value as the identifier:

EntityWithIntegerId entity = session.Load<EntityWithIntegerId>(1);

Converting to String Identifier

Even if the identifier is a string, you can use the Load<T>(ValueType) overload. The client is aware of the ID generation conventions (collectionName/number), so you could load the entity with the key employees/1 by using the code:

Employee employee = session.Load<Employee>(1);

Load with Includes

When there is a 'relationship' between documents, those documents can be loaded into a single request call using the Include + Load methods.

ILoaderWithInclude<object> Include(string path);

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

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

Example I

// 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

Example II

// 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

Example III

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

Supplier supplier = session.Load<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.

TResult[] Load<TResult>(IEnumerable<string> ids);

TResult[] Load<TResult>(IEnumerable<ValueType> ids);

TResult[] Load<TResult>(params ValueType[] ids);

TResult[] Load<TResult>(
	IEnumerable<string> ids,
	string transformer,
	Action<ILoadConfiguration> configure = null);

TResult[] Load<TResult>(
	IEnumerable<string> ids,
	Type transformerType,
	Action<ILoadConfiguration> configure = null);

TResult[] Load<TTransformer, TResult>(
	IEnumerable<string> ids,
	Action<ILoadConfiguration> configure = null)
	where TTransformer : AbstractTransformerCreationTask, new();
Parameters
ids IEnumerable or IEnumerable or ValueType[] Enumerable or array of IDs that should be loaded.
transformer or transformerType string or Type Name or type of a transformer to use on loaded documents.
configure Action Additional configuration that should be used during an operation e.g. transformer parameters can be added.
Return Value
TResult[] Array of entities in the exact same order as given IDs. If document does not exist, value at the appropriate position in array will be null.

Example I

Employee[] employees = session.Load<Employee>(new List<string> { "employees/1", "employees/2" });
Employee employee1 = employees[0];
Employee employee2 = employees[1];

Example II

// loading 'employees/1' and 'employees/2'
// and transforming results using 'Employees_NoLastName' transformer
// which returns 'LastName' as 'null'
Employee[] employees = session
	.Load<Employees_NoLastName, Employee>(new List<string> { "employees/1", "employees/2" });
Employee employee1 = employees[0];
Employee employee2 = employees[1];

LoadStartingWith

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

TResult[] LoadStartingWith<TResult>(
	string keyPrefix,
	string matches = null,
	int start = 0,
	int pageSize = 25,
	string exclude = null,
	RavenPagingInformation pagingInformation = null,
	string skipAfter = null);

TResult[] LoadStartingWith<TTransformer, TResult>(
	string keyPrefix,
	string matches = null,
	int start = 0,
	int pageSize = 25,
	string exclude = null,
	RavenPagingInformation pagingInformation = null,
	Action<ILoadConfiguration> configure = null,
	string skipAfter = null);
Parameters
keyPrefix string the prefix for which documents should be returned
matches string pipe ('|') separated values for which document keys (after 'keyPrefix') should be matched ('?' any single character, '*' any characters)
start int the number of documents that should be skipped
pageSize int the maximum number of documents that will be retrieved
pagingInformation RavenPagingInformation used to perform rapid pagination on the server side
exclude string pipe ('|') separated values for which document keys (after 'keyPrefix') should not be matched ('?' any single character, '*' any characters)
configure Action Additional configuration that should be used during an operation e.g. transformer parameters can be added.
skipAfter string skip document fetching until given key is found and return documents after that key (default: null)
Return Value
TResult[] Array of entities matching given parameters.

Example I

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

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);

Example III

// return up to 128 entities with Id that starts with 'employees/' 
// and rest of the Id have length of 3, begins and ends with "1" 
// and contains any character at 2nd position e.g. employees/101, employees/1B1
// and transform results using 'Employees_NoLastName' transformer
Employee[] result = session
	.Advanced
	.LoadStartingWith<Employees_NoLastName, Employee>("employees/", "1?1", 0, 128);

Stream

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

IEnumerator<StreamResult<T>> Stream<T>(
    Etag fromEtag, 
    int start = 0, 
    int pageSize = int.MaxValue, 
    RavenPagingInformation pagingInformation = null, 
    string transformer = null, 
    Dictionary<string, RavenJToken> transformerParameters = null);

IEnumerator<StreamResult<T>> Stream<T>(
    string startsWith, 
    string matches = null, 
    int start = 0, 
    int pageSize = int.MaxValue, 
    RavenPagingInformation pagingInformation = null, 
    string skipAfter = null, 
    string transformer = null, 
    Dictionary<string, RavenJToken> transformerParameters = null);
Parameters
fromEtag Etag ETag of a document from which stream should start (mutually exclusive with 'startsWith')
startsWith string prefix for which documents should be streamed (mutually exclusive with 'fromEtag')
matches string pipe ('|') separated values for which document keys (after 'keyPrefix') 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
pagingInformation RavenPagingInformation used to perform rapid pagination on the server side
skipAfter string skip document fetching until given key is found and return documents after that key (default: null)
transformer String name of transformer (default: null)
transformerParameters Dictionary<string, RavenJToken> parameters to pass to the transformer (default: null)
Return Value
IEnumerator<StreamResult> Enumerator with entities.

Example I

IEnumerator<StreamResult<Employee>> enumerator = session.Advanced.Stream<Employee>("employees/");
while (enumerator.MoveNext())
{
	StreamResult<Employee> employee = enumerator.Current;
}

Example 2

Using the following transformer:

public class SimpleTransformer : AbstractTransformerCreationTask
{
    public class Result
    {
        public string Name { get; set; }
    }

    public override TransformerDefinition CreateTransformerDefinition(bool prettify = true)
    {
        return new TransformerDefinition
        {
            Name = "SimpleTransformer",
            TransformResults = "from r in results select new { Name = Parameter(\"Name\") }"
        };
    }
}

StreamDocs using the SimpleTransformer defined above and one supplied parameter:

var transformer = new SimpleTransformer();
transformer.Execute(store);

using (IEnumerator<StreamResult<SimpleTransformer.Result>> enumerator = session.Advanced.Stream<SimpleTransformer.Result>("people/", transformer: transformer.TransformerName, transformerParameters: new Dictionary<string, RavenJToken> { { "Name", "Bill" } }))
{
    while (enumerator.MoveNext())
    {
        StreamResult<SimpleTransformer.Result> result = enumerator.Current;
        string name = result.Document.Name;
        Assert.Equal("Bill", name); // Should be true
    }
}

Remarks

Information

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

Caution

fromEtag does not do any filtrations on the server-side based on the specified in streaming function return type (e.g. Employee). It will return all documents from given Etag even if their Raven-Clr-Type does not match the return type, which may cause potential casting errors. Set return type to object, dynamic or RavenJObject to address a situation where documents with different types might be returned.

IsLoaded

To check if an entity is attached to a session, e.g. it has been loaded previously, use the IsLoaded method from the Advanced session operations.

IsLoaded checks if you've already tried to load a document during the current session.
If you try to load a document that no longer exists with the Load method (perhaps it has been deleted),
IsLoaded will then return true because IsLoaded shows that you've already tried to load the non-existent document.

bool IsLoaded(string id);
Parameters
id string Entity Id for which the check should be performed.
Return Value
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