You can build a database-backed search in a ViewModel by using a Seeker, which is intended for users who need to find a small, relevant set of objects from a large persistent database.
Search large data sets with a Seeker
A Seeker is a nested ViewModel class that runs search criteria against persistent storage and places the matching objects in a result collection. Use it when the user must search a database before opening or working with an object, such as finding a person by name from many thousands of persons.
MDriven evaluates Seeker criteria as OCLps (OCL Persistence Storage). OCLps is an OCL form that MDriven can translate to SQL and execute in the database. This lets the database perform the filtering instead of loading every candidate object into the Prototyper or server memory.
For an introduction to the underlying database language, see SQL. For the broader search design and paging considerations, see Documentation:Tables, search and ordering.
Create a Seeker
Create the search structure in MDriven Designer:
- Create or open the ViewModel that will contain the search.
- Right-click the ViewModel.
- Select Add Nested ViewModel class.
- Choose Add Search Expressions.
- Add the input variables that the user will set, and add one or more search criteria that refer to those variables.
- Bind the result collection to a table, picker, or other user-interface element that displays the found objects.
The generated search structure provides conventions that MDriven uses for searching. The key convention is the result variable described below.
Required parts of the search
| Part | Purpose | Example |
|---|---|---|
| Search variable | Holds a value supplied by the user or set by the ViewModel. A variable can be used by one or more criteria. | vSeekString contains the text Smith.
|
| Search expression (criterion) | An OCLps expression that defines which objects to find. MDriven translates it to SQL for database execution. | Find persons whose last name starts with the entered text. |
vSeekerResult
|
The collection variable that receives the search result and is used to display or otherwise consume the found objects. | A table shows the persons in vSeekerResult.
|
A Seeker must have a collection variable named vSeekerResult. The name is significant: it identifies the collection that receives the result of the search expression.
Write criteria for the database
Search criteria use OCLps, not ordinary in-memory navigation. The expression must be suitable for translation and execution in the database.
For example, a text search can find persons whose first or last name starts with the value in vSeekString:
Person.allinstances->select(a|
a.FirstName.SqlLike(vSeekString+'%')
)->union(
Person.allinstances->select(a|
a.LastName.SqlLike(vSeekString+'%')
)
)If vSeekString is Smith, this expression can return persons with a first name or last name beginning with "Smith". The union makes one search field useful for more than one name field.
Use a typed variable for typed data. For date filtering, use a DateTime variable rather than passing a date as text. For example:
Person.allInstances->select(p|
p.Registrered>=vAfterDate
)->orderBy(p|p.Registrered)This finds persons registered on or after vAfterDate and orders the returned set by registration date. See Training:Seeker view for more search-expression examples and guidance on date variables.
Combine and activate criteria
You can add several criteria to the same Seeker. The server intersects their results, meaning an object must meet every active criterion to appear in vSeekerResult.
Give optional criteria an activation condition so that an empty input does not unintentionally limit the result. An Active Expression is optional; when it is blank, the criterion is active by default.
For example, a person search may have:
- a name criterion, active when the name variable has a value;
- a registration-date criterion, active when
vAfterDatehas been set; - a status criterion, active when the user has selected a status.
When all three are active, the result contains only persons matching the name, date, and status. When only the name criterion is active, the search is limited by name only.
Use search batches deliberately
A Seeker can have multiple batches of search expressions. The first batch runs when the user starts a search. If the user starts the search again without changing any search variables, MDriven uses the next batch. When a variable changes, MDriven resets the sequence and uses the first batch again.
This supports progressive alternatives for one input. For example, with a single number field you can use successive batches to try:
- product code;
- order number;
- customer phone number.
Use batches only when repeated searches with unchanged input are understandable to users. If users need to see all matching interpretations at once, use one criterion that combines the alternatives, such as a union expression.
Control result size and ordering
Do not design a search to return every matching object when the database may contain a large number of matches. A short prefix such as A can match many rows; loading all of them is not useful when the user's goal is to choose one object.
Searching, filtering, and ordering have separate responsibilities:
- Search finds objects from the database based on entered text or other criteria.
- Filter limits results based on selected parameters or context.
- Ordering determines the presentation order.
When the interface shows only part of a result set, changing the sort order must rerun the database search. Sorting only the currently loaded rows does not sort the complete matching set. See Documentation:Tables, search and ordering for the consequences of paging, server-side filtering, and ordering.
Derivations, constraints, and validation
A Seeker is a retrieval mechanism: it finds persistent objects and resolves the returned identities to objects for the ViewModel. It does not replace model derivations, constraints, or validation rules.
Keep each concern separate:
- Use derivations to calculate model values.
- Use constraints and validation rules to enforce or report valid model state.
- Use Seeker criteria to decide which existing persistent objects to retrieve.
For example, a search may return a person because the person matches LastName.SqlLike(vSeekString+'%'). Any derivations and validation behavior remain part of the model and apply when that person is loaded and worked with.
When to use other database expressions
Use a Seeker when you need a ViewModel search that returns objects for the user to select or inspect. For direct database-oriented calculations or values, such as aggregate operations over a large amount of data, see PSExpression, or how to do things in the DB from MDriven.
