Queries that return objects directly from the in-memory model should be avoided. Objects are seldom isolated, they have references to other objects which have references to yet other objects and so on.
For a highly interconnected model, returning an entity or collection of entities will result in a lot of related data being extracted from the model. At worst, the entire model could be returned! The data returned is usually serialized, could contain sensitive information and exposes unwanted behavior and properties in the calling context. One way to address this issue is using views.
Consider the model below. A Product
has a reference to one or more Category
objects. Each Category
has a list of Product
objects. A single product contains a reference to 0 or more categories, and each category references a number of products resulting in an object graph.
Now say we want to display a dropdown list with categories. We want the name and id. Here’s what a beginner might do:
It’ll work but way too much data is being serialized and returned. Besides the category objects, every Product that has at least one category will also be returned.
You might think the following is a good idea:
Here’s a better way to do it:
Note how the CategoryView
constructor takes a Category
parameter. This is just one way to do it. What’s important here is that the mapping is taking place within the Execute-method.
The CategoryView
class might look something like this:
Note the IImmutable interface. It will cause the engine to skip serialization because the result and model are isolated.
Ad-hoc lambda queries in application code aren’t always desirable, they can become a bit messy, they only work with an embedded engine and are more difficult to test. So here’s another approach using a custom query class. It’s cleaner and supports client/server.
Returning specific view objects from commands and queries is a good practice with multiple benefits: