Perform requests lazily
-
Lazy request:
-
You can define a lazy request within a session (e.g. a lazy-query or a lazy-load request)
and defer its execution until actually needed. -
The lazy request definition is stored in the session and a
Lazy<T>
instance is returned.
The request will be sent to the server and executed only when you access the value of this instance.
-
-
Multiple lazy requests:
-
Multiple lazy requests can be defined within the same session.
-
When triggering the deferred execution (whether implicitly or explicitly),
ALL pending lazy requests held up by the session will be sent to the server in a single call.
This can help reduce the number of remote calls made to the server over the network.
-
-
In this page:
Operations that can be executed lazily
Load entities
Load loads a document entity from
the database into the session.
Loading entities can be executed lazily.
Lazy<Employee> lazyEmployee = session
// Add a call to Lazily
.Advanced.Lazily
// Document will Not be loaded from the database here, no server call is made
.Load<Employee>("employees/1-A");
Employee employee = lazyEmployee.Value; // 'Load' operation is executed here
// The employee entity is now loaded & tracked by the session
Load entities with include
Load with include loads both the document and the specified related document.
Loading entities with include can be executed lazily.
Lazy<Product> lazyProduct = session
// Add a call to Lazily
.Advanced.Lazily
// Request to include the related Supplier document
// Documents will Not be loaded from the database here, no server call is made
.Include<Product>(x => x.SupplierId)
.Load<Product>("products/1-A");
// 'Load with include' operation will be executed here
// Both documents will be retrieved from the database
Product product = lazyProduct.Value;
// The product entity is now loaded & tracked by the session
// Access the related document, no additional server call is made
Supplier supplier = session.Load<Supplier>(product.SupplierId);
// The supplier entity is now also loaded & tracked by the session
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string SupplierId { get; set; } // The related document ID
}
Load entities starting with
LoadStartingWith loads entities whose ID starts with the specified prefix.
Loading entities with a common prefix can be executed lazily.
Lazy<Dictionary<string, Employee>> lazyEmployees = session
// Add a call to Lazily
.Advanced.Lazily
// Request to load entities whose ID starts with 'employees/'
// Documents will Not be loaded from the database here, no server call is made
.LoadStartingWith<Employee>("employees/");
var employees = lazyEmployees.Value; // 'Load' operation is executed here
// The employee entities are now loaded & tracked by the session
Conditional load
ConditionalLoad logic is:
- If the entity is already loaded to the session:
no server call is made, the tracked entity is returned. - If the entity is Not already loaded to the session:
the document will be loaded from the server only if the change-vector provided to the method is older than the one in the server (i.e. if the document in the server is newer). - Loading entities conditionally can be executed lazily.
// Create document and get its change-vector:
string changeVector;
using (var session1 = store.OpenSession())
{
Employee employee = new Employee();
session1.Store(employee, "employees/1-A");
session1.SaveChanges();
// Get the tracked entity change-vector
changeVector = session1.Advanced.GetChangeVectorFor(employee);
}
// Conditionally lazy-load the document:
using (var session2 = store.OpenSession())
{
var lazyEmployee = session2
// Add a call to Lazily
.Advanced.Lazily
// Document will Not be loaded from the database here, no server call is made
.ConditionalLoad<Employee>("employees/1-A", changeVector);
var loadedItem = lazyEmployee.Value; // 'ConditionalLoad' operation is executed here
Employee employee = loadedItem.Entity;
// If ConditionalLoad has actually fetched the document from the server (logic described above)
// then the employee entity is now loaded & tracked by the session
}
Run query
A Query can be executed lazily.
Learn more about running queries lazily in lazy queries.
// Define a lazy query:
Lazy<IEnumerable<Employee>> lazyEmployees = session
.Query<Employee>()
.Where( x => x.FirstName == "John")
// Add a call to Lazily, the query will Not be executed here
.Lazily();
IEnumerable<Employee> employees = lazyEmployees.Value; // Query is executed here
// Note: Since query results are not projected,
// then the resulting employee entities will be tracked by the session.
Get revisions
All methods for getting revisions and their metadata can be executed lazily.
Lazy<List<Employee>> lazyRevisions = session
// Add a call to Lazily
.Advanced.Revisions.Lazily
// Revisions will Not be fetched here, no server call is made
.GetFor<Employee>("employees/1-A");
// Usage is the same for the other get revisions methods:
// .Get()
// .GetMetadataFor()
List<Employee> revisions = lazyRevisions.Value; // Getting revisions is executed here
Get compare-exchange value
Getting compare-exchange values can be executed lazily.
using (var session =
store.OpenSession(new SessionOptions { TransactionMode = TransactionMode.ClusterWide }))
{
// Create compare-exchange value:
session.Advanced.ClusterTransaction
.CreateCompareExchangeValue(key: "someKey", value: "someValue");
session.SaveChanges();
// Get the compare-exchange value lazily:
Lazy<CompareExchangeValue<string>> lazyCmpXchg = session
// Add a call to Lazily
.Advanced.ClusterTransaction.Lazily
// Compare-exchange values will Not be fetched here, no server call is made
.GetCompareExchangeValue<string>("someKey");
// Usage is the same for the other method:
// .GetCompareExchangeValues()
CompareExchangeValue<string> cmpXchgValue =
lazyCmpXchg.Value; // Getting compare-exchange value is executed here
}
Multiple lazy requests
Execute all requests - implicitly
Accessing the value of ANY of the lazy instances will trigger the execution of ALL pending lazy requests held up by the session, in a SINGLE server call.
// Define multiple lazy requests
Lazy<User> lazyUser1 = session.Advanced.Lazily.Load<User>("users/1-A");
Lazy<User> lazyUser2 = session.Advanced.Lazily.Load<User>("users/2-A");
Lazy<IEnumerable<Employee>> lazyEmployees = session.Query<Employee>()
.Lazily();
Lazy<IEnumerable<Product>> lazyProducts = session.Query<Product>()
.Search(x => x.Name, "Ch*")
.Lazily();
// Accessing the value of ANY of the lazy instances will trigger
// the execution of ALL pending lazy requests held up by the session
// This is done in a SINGLE server call
User user1 = lazyUser1.Value;
// ALL the other values are now also available
// No additional server calls are made when accessing these values
User user2 = lazyUser2.Value;
IEnumerable<Employee> employees = lazyEmployees.Value;
IEnumerable<Product> products = lazyProducts.Value;
Execute all requests - explicitly
Explicitly calling ExecuteAllPendingLazyOperations
will execute
ALL pending lazy requests held up by the session, in a SINGLE server call.
// Define multiple lazy requests
Lazy<User> lazyUser1 = session.Advanced.Lazily.Load<User>("users/1-A");
Lazy<User> lazyUser2 = session.Advanced.Lazily.Load<User>("users/2-A");
Lazy<IEnumerable<Employee>> lazyEmployees = session.Query<Employee>()
.Lazily();
Lazy<IEnumerable<Product>> lazyProducts = session.Query<Product>()
.Search(x => x.Name, "Ch*")
.Lazily();
// Explicitly call 'ExecuteAllPendingLazyOperations'
// ALL pending lazy requests held up by the session will be executed in a SINGLE server call
session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();
// ALL values are now available
// No additional server calls are made when accessing the values
User user1 = lazyUser1.Value;
User user2 = lazyUser2.Value;
IEnumerable<Employee> employees = lazyEmployees.Value;
IEnumerable<Product> products = lazyProducts.Value;