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