Query

Query

Looking up collections of data to be presented to users in a view is a common scenario in applications. Dolittle formalizes this through Query-types. These types become the contract for your query capabilities. Queries can be optimized for the datasource as you see fit for the feature they’re being used in.

QueryFor

To implement a query, you need to implement the interface IQueryFor<>.
The generic type argument should point to a read model.
This is a marker interface and does not require you implement anything specific.
Instead it is relying on a default convention; its looking for a public property called Query with a return type of IQueryable<T> where T : IReadModel.

Dolittle recognizes the return types and will look for a query provider
for the type returned.

The implementation of the query can be anything you want it to be. Use whatever underlying datastore and technique to get to the data. The only rule is that there
must be a query provider for the return type.

Dolittle has a very simple repository for read models that can be used. You don’t have to use it, as you decide entirely what you use internally - the query sits there as a contract and can also then be changed to accommodate a change in storage strategy.

Arguments

With queries, sometimes you need to filter based on input. Any public property with
a getter and a setter is considered an argument for the query.

Validation

The arguments can have validators associated with them. All you need to do is to create something
that inherits from QueryValidationDescriptorFor<> and point the generic argument to the
query type.

usingDolittle.Validation;usingDolittle.Read.Validation;publicclassEmployeeHiredAfterValidator:QueryValidationDescriptorFor<EmployeesHiredAfter>{publicEmployeeHiredAfterValidator(){// Require that hiring date is set after a certain date
ForArgument(e=>e.HiredAfter).HasToBeGreaterThan(newDateTime(1985,1,1));}}

Paging

Paging can be supported through the query provider
deals with. Paging is a frontend concern and should not something you need to think about.
In fact, paging is ideally a view concern, something decided as part of the interaction design.
The client representations of queries has functionality related to paging.

The QueryProvider model for IQueryable only works with paging if there is a Linq provider that supports deferred execution and no-one in the chain has called ToList or ToArray.

Filtering

Some features require filtering the read models on a model level. This could for instance be
row level security with complex scenarios making it easier to do it as a post process after
data has been received from the datasource.