Session: Querying: How to perform projection?

There are a couple types of projections:

Select

The most common projection is done by using LINQ Select method.

Example I

// request 'FirstName' and 'LastName' from server
// and project it to anonymous class
var results = session
	.Query<Employee>()
	.Select(x => new
	{
		FirstName = x.FirstName,
		LastName = x.LastName
	})
	.ToList();

Example II

// request 'FirstName' and 'LastName' from server
// and project it to 'EmployeeFirstAndLastName'
List<EmployeeFirstAndLastName> results = session
	.Query<Employee>()
	.Select(x => new EmployeeFirstAndLastName
	{
		FirstName = x.FirstName,
		LastName = x.LastName
	})
	.ToList();

TransformWith

Detailed article about using transformers with queries can be found here.

ProjectFromIndexFieldsInto

This extension method uses reflection to extract all public fields and properties to fetch and perform projection to the requested type.

Example

// request all public fields/properties available 
// in 'EmployeeFirstAndLastName' ('FirstName' and 'LastName')
// and project it to instance of this class
List<EmployeeFirstAndLastName> results = session
	.Query<Employee>()
	.ProjectFromIndexFieldsInto<EmployeeFirstAndLastName>()
	.ToList();

OfType (As) - simple projection

OfType or As is a client-side projection. The easiest explanation of how it works is: take results that server returned and map them to given type. This may become useful when querying index that contains fields that are not available in mapped type.

Example

public class Products_BySupplierName : AbstractIndexCreationTask<Product>
{
	public class Result
	{
		public string Name { get; set; }
	}

	public Products_BySupplierName()
	{
		Map =
			products =>
			from product in products
			let supplier = LoadDocument<Supplier>(product.Supplier)
			select new
				       {
					       Name = supplier.Name
				       };
	}
}

// query index 'Products_BySupplierName' 
// return documents from collection 'Products' that have a supplier 'Norske Meierier'
// project them to 'Products'
List<Product> results = session
	.Query<Products_BySupplierName.Result, Products_BySupplierName>()
	.Where(x => x.Name == "Norske Meierier")
	.OfType<Product>()
	.ToList();

Remarks

Note

Projections request from server an array of fields to download, if index contains those fields (stores them) they will come directly from index, if not values from document will be used. You can read more about storing fields here.

Raven/ImplicitFetchFieldsFromDocumentMode setting can be altered to change the behavior of field fetching. By default it allows fetching fields from document if index is missing them (they are not stored), but this can be changed to skipping those fields or even throwing an exception. Read more about this configuration option here.

Note

Projected entities (even named types) are not being tracked by session.