This is the preferred way of defining queries. In the derived class, write your query by overriding Execute, which accepts the in-memory model and returns the result. It can be as simple as looking up an object by key or some arbitrarily complex calculation.
Two example queries:
Lambda queries are simply generic functions that take the model as input and return some value. They’re suitable for simple queries, ad-hoc querying with scriptcs, LinqPad or the OrigoDB server web ui. Example given the same model as above:
Parameterized lambda queries
The example above uses the constant 42 but of course you can use variables, parameters, objects and methods etc from the calling context. Here’s an Asp.NET MVC action:
As you can see this can get messy fast, not to mention how difficult it is to test. A pattern which solves this problem is using query functions, functions that take parameters and return lambda queries:
Mark your query classes with a Serializable attribute to ensure they can be passed to a remote origodb server.
Lambdas/expression trees can’t easily be sent across the wire. So the Engine.Execute overload which takes a Func is not available on the IEngine interface returned by Engine.For<TModel>(). If you know you have a local engine, cast from IEngine to Engine to access the overload.
Queries and transactions
Queries are fully isolated from commands, the state of the model will not change while the query is executing (unless you change the default ISynchronizer).
Query result cloning
To protect you from returning references to mutable objects, query results are deep cloned. See Views
For optimal throughput and low latency, queries (and commands) should execute as quickly as possible. Some guidelines:
* Don’t do anything unnecessary within the execute method, do it before or after.
* Tune your models data structures and algorithms for optimal runtime performance.
* Return as little data as possible, minimizing the cost of serialization
* Return immutable results, they will not be cloned