Perform requests lazily



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