Lazy Operations

Some of the operations in RavenDB can be evaluated lazily (performed only when needed).

This section will describe each of the available lazy operations:
* Querying
* Loading
* Faceted searching
* Suggesting

Querying

To perform query below

IEnumerable<User> users = session
	.Query<User>()
	.Where(x => x.Name == "john");

as a lazy operation we have introduced Lazily() extension method that will mark any type of queries as a lazy operation, so to perform above query as such an operation just mark it with this extension method like in example below.

Lazy<IEnumerable<User>> lazyUsers = session
	.Query<User>()
	.Where(x => x.Name == "John")
	.Lazily();

To evaluate our lazyUsers just access Value property.

IEnumerable<User> users = lazyUsers.Value;

An action that will be executed when value gets evaluated can be passed to Lazily. It is very handy in scenarios when you want to perform additional actions when value gets evaluated or when you want to execute all pending lazy operations at once.

IEnumerable<User> users = null;
IEnumerable<City> cities = null;

session
	.Query<User>()
	.Where(x => x.Name == "John")
	.Lazily(x => users = x);

session
	.Query<City>()
	.Where(x => x.Name == "New York")
	.Lazily(x => cities = x);

session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

Lazily is a part of LinqExtensions available in Raven.Client namespace, so

using Raven.Client;

is mandatory.

Lazy Lucene queries are also possible.

Lazy<IEnumerable<User>> users = session.Advanced
	.LuceneQuery<User>()
	.WhereEquals("Name", "John")
	.Lazily();

Loading

Loading lazily is done in a bit different manner, it can be achieved by using one of the methods available in session.Advanced.Lazily property, so to perform below query

User user = session.Load<User>("users/1");

as a lazy operation just use one of the methods from session.Advanced.Lazily like in example below

Lazy<User> lazyUser = session.Advanced.Lazily.Load<User>("users/1");

Value can be evaluated in same way as when Querying and Action that will be performed when value gets evaluated can also be passed.

User user = lazyUser.Value;

User user = null;

session.Advanced.Lazily.Load<User>("users/1", x => user = x);
session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

Other available lazy loading methods are:
1. LoadStartingWith where you can load all users with given key prefix.

var users = session.Advanced.Lazily.LoadStartingWith<User>("users/1");

2. Includes where additional documents will be loaded by given path.

If we consider having User and City classes as defined below

private class User
{
	public string Id { get; set; }

	public string Name { get; set; }

	public string CityId { get; set; }
}

private class City
{
	public string Id { get; set; }

	public string Name { get; set; }
}

and store one User and City

using (var session = store.OpenSession())
{
	var user = new User
				   {
					   Id = "users/1",
					   Name = "John",
					   CityId = "cities/1"
				   };

	var city = new City
				   {
					   Id = "cities/1",
					   Name = "New York"
				   };

	session.Store(user);
	session.Store(city);
	session.SaveChanges();
}

then we will be able to perform code such as

var lazyUser = session.Advanced.Lazily
	.Include("CityId")
	.Load<User>("users/1");

var user = lazyUser.Value;
var isCityLoaded = session.Advanced.IsLoaded("cities/1"); // will be true

To take advantage of lazy Faceted search use ToFacetsLazy() extension method from LinqExtensions found in Raven.Client namespace.

To change Faceted search from last step described here to lazy operation just substitute ToFacets with ToFacetsLazy.

Lazy<FacetResults> lazyFacetResults = session
	.Query<Camera>("CameraCost")
	.Where(x => x.Cost >= 100 && x.Cost <= 300)
	.ToFacetsLazy("facets/CameraFacets");

FacetResults facetResults = lazyFacetResults.Value;

Suggesting

Similar practice as in Faceted search has been used in lazy suggestions. The SuggestLazy() extension method is available in LinqExtensions and can be used as a substitution to Suggest() to mark operation as a lazy one.

Lazy<SuggestionQueryResult> lazySuggestionResult = session
	.Query<User>()
	.Where(x => x.Name == "John")
	.SuggestLazy();

SuggestionQueryResult suggestionResult = lazySuggestionResult.Value;