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
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
.
/** @var Lazy<Employee> $lazyEmployee */
$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::class, "employees/1-A");
$employee = $lazyEmployee->getValue(); // '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
.
/** @var Lazy<Product> $lazyProduct */
$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("SupplierId")
->load(Product::class, "products/1-A");
// 'Load with include' operation will be executed here
// Both documents will be retrieved from the database
$product = $lazyProduct->getValue();
// The product entity is now loaded & tracked by the session
// Access the related document, no additional server call is made
$supplier = $session->load(Supplier::class, $product->getSuppierId());
// The supplier entity is now also loaded & tracked by the session
class Product
{
public ?string $id = null;
public ?string $name = null;
public ?string $supplierId = null;
public function getId(): ?string
{
return $this->id;
}
public function setId(?string $id): void
{
$this->id = $id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getSupplierId(): ?string
{
return $this->supplierId;
}
public function setSupplierId(?string $supplierId): void
{
$this->supplierId = $supplierId;
} // The related document ID
}
Load entities starting with
load_starting_with loads
entities whose ID starts with the specified prefix.
Loading entities with a common prefix can be executed lazily
.
/** @var Lazy<array<Employee>> $lazyEmployees */
$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::class, "employees/");
$employees = $lazyEmployees->getValue(); // 'Load' operation is executed here
// The employee entities are now loaded & tracked by the session
Conditional load
conditional_load 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:
$changeVector = null;
$session1 = $store->openSession();
try {
$employee = new Employee();
$session1->store($employee, "employees/1-A");
$session1->saveChanges();
// Get the tracked entity change-vector
$changeVector = $session1->advanced()->getChangeVectorFor($employee);
} finally {
$session1->close();
}
// Conditionally lazy-load the document:
$session2 = $store->openSession();
try {
$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::class, "employees/1-A", $changeVector);
var
$loadedItem = $lazyEmployee->getValue(); // 'ConditionalLoad' operation is executed here
$employee = $loadedItem->getEntity();
// If ConditionalLoad has actually fetched the document from the server (logic described above)
// then the employee entity is now loaded & tracked by the session
} finally {
$session2->close();
}
Run query
A query can be executed lazily
.
Learn more about running queries lazily in lazy queries.
// Define a
// lazy query:
$lazyEmployees = $session
->query(Employee::class)
->whereEquals("FirstName", "John")
// Add a call to Lazily, the query will Not be executed here
->lazily();
$employees = $lazyEmployees->getValue(); // 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
.
/** @var Lazy<array<Employee>> $lazyRevisions */
$lazyRevisions = $session
// Add a call to Lazily
->advanced()->revisions()->lazily()
// Revisions will Not be fetched here, no server call is made
->getFor(Employee::class, "employees/1-A");
// Usage is the same for the other get revisions methods:
// .Get()
// .GetMetadataFor()
/** @var array<Employee> $revisions */
$revisions = $lazyRevisions->getValue(); // Getting revisions is executed here
Get compare-exchange value
get_compare_exchange_value
can be executed lazily
.
$sessionOptions = new SessionOptions();
$sessionOptions->setTransactionMode(TransactionMode::clusterWide());
$session = $store->openSession($sessionOptions);
try {
// Create compare-exchange value:
$session->advanced()->clusterTransaction()
->createCompareExchangeValue(key: "someKey", value: "someValue");
$session->SaveChanges();
// Get the compare-exchange value lazily:
/** @var Lazy<CompareExchangeValue<string>> $lazyCmpXchg */
$lazyCmpXchg = $session
// Add a call to Lazily
->advanced()->clusterTransaction()->lazily()
// Compare-exchange values will Not be fetched here, no server call is made
->getCompareExchangeValue(null, "someKey");
// Usage is the same for the other method:
// .GetCompareExchangeValues()
/** @var CompareExchangeValue<string> $cmpXchgValue */
$cmpXchgValue = $lazyCmpXchg->getValue(); // Getting compare-exchange value is executed here
} finally {
$session->close();
}
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
$lazyUser1 = $session->advanced()->lazily()->load(User::class, "users/1-A");
$lazyUser2 = $session->advanced()->lazily()->load(User::class, "users/2-A");
$lazyEmployees = $session->query(Employee::class)
->lazily();
$lazyProducts = $session->query(Product::class)
->search("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
$user1 = $lazyUser1->getValue();
// ALL the other values are now also available
// No additional server calls are made when accessing these values
$user2 = $lazyUser2->getValue();
$employees = $lazyEmployees->getValue();
$products = $lazyProducts->getValue();
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
$lazyUser1 = $session->advanced()->lazily->load(User::class, "users/1-A");
$lazyUser2 = $session->advanced()->lazily->load(User::class, "users/2-A");
$lazyEmployees = $session->query(Employee::class)
->lazily();
$lazyProducts = $session->query(Product::class)
->search("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
$user1 = $lazyUser1->getValue();
$user2 = $lazyUser2->getValue();
$employees = $lazyEmployees->getValue();
$products = $lazyProducts->getValue();