🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Seeker view
This page was created by Alexandra on 2017-09-27. Last edited by Wikiadmin on 2026-07-29.

A Seeker is a special ViewModel that lets users search persistent data before opening or working with a found object; use it when a view has no initial root object.

What a Seeker does

A normal document ViewModel starts from a known object. A Seeker starts without one. It accepts search values from the user, evaluates its search criteria against persistent storage, and places the matching objects in a result collection.

A typical user flow is:

  1. Enter one or more search values.
  2. Select Search.
  3. Review the matching rows.
  4. Open, select, or otherwise continue with a found object.

For example, a user can search for people by name and department, then open one person in a document ViewModel. This search-then-work pattern is a common entry point to an application.

How seeker searches are evaluated

Seeker criteria use OCL-PS (Object Constraint Language—Persistent Storage). OCL-PS expressions are evaluated against persistent storage rather than against an already loaded in-memory object graph.

When the application uses a SQL database, MDriven translates the OCL-PS search expression to the database query language and lets the database evaluate it. This is important when the database contains many objects: filter the data in persistent storage before loading results into the ViewModel.

For a guided introduction to OCL-PS, the Action Language, and the OCL debugger, follow Training:Bootcamp:Chapter 4.

Required seeker parts

A practical Seeker has the following parts:

Part Purpose Example
Search-input variables Hold values entered by the user. vSeekString:String holds text; a variable typed as ReferenceClass holds a selected reference object.
Input columns Expose the search-input variables in the seeker form. Add a column for vSeekString; present a reference variable as a PickList.
Search expressions and criteria Define the persistent-storage queries used to find objects. Find Person objects whose name starts with the entered text.
vSeekerResult Holds the collection returned by the seeker logic. A Person seeker normally has vSeekerResult:Collection(Person).

The vSeekerResult contract

The one required convention is a variable named vSeekerResult with a collection type. The seeker logic places its search result in this variable.

When you add the first search expression, MDriven Designer adds default seeker implementation details, including vSeekerResult and a vSeekString variable. These generated columns and widgets are a starting point, not a requirement. You can change the input UI and variables to suit the search.

By default, vSeekerResult is created as a collection of the ViewModel root type. To search for another type, declare it explicitly. For example, a ViewModel rooted in one type can search products by declaring:

vSeekerResult:Collection(Product)

The seeker logic then treats Product as the search-result type.

Build a multi-variable Seeker

Use separate variables and criteria when users need to combine independent limits, such as text and department.

  1. In MDriven Designer, open the Seeker ViewModel.
  2. Declare a variable for each value the user can supply. For example, declare a string variable for name text and an object-reference variable typed as ReferenceClass for a selected reference.
  3. Add ViewModel columns that use those variables so the user can enter the values. Configure the reference-value column as a PickList.
  4. Right-click a ViewModelColumn and select Add nested > Add search expr. This creates the search-expression nesting.
  5. Add a criterion for each independent filter. Each criterion must return the collection type used by vSeekerResult.
  6. Add an Active Expression to criteria that should apply only when the corresponding input has a value.
  7. Save and test the Seeker with each filter separately and with both filters supplied.

Criteria are intersected

Within a search batch, the seeker intersects the results from active criteria. In other words, an object must match every active criterion to appear in the result.

For example, if one criterion finds people matching a name and a second finds people in the selected department, the result contains only people that match both the name and the department.

This makes Active Expressions essential for optional filters. A criterion that is active while its input is empty can unintentionally remove all results.

Active Expressions

An Active Expression determines whether a criterion participates in the current search. If you leave it blank, it defaults to true, so the criterion is always active.

For a numeric search input, activate the criterion only when the entered text can be parsed as an integer:

vSeekIntValue.notnull

The Bootcamp seeker exercise demonstrates this with a Person age criterion:

Person.allinstances->select(p|p.Age>=vSeekIntValue)

This criterion finds people whose age is greater than or equal to the entered value, but only when vSeekIntValue is not null.

Search batches and repeated Search

A Seeker can contain multiple batches of search expressions. This supports a compact search form where repeated searches try different interpretations of unchanged input.

The rules are:

  • The first click of Search uses the first batch.
  • If the user clicks Search again without changing any search variable, the next batch is used.
  • Further unchanged searches continue through the batches in round-robin order.
  • Changing any search variable resets the sequence, so the next search starts again with the first batch.

For example, a single text field can support several likely identifiers:

  1. First search: match a product code.
  2. Second unchanged search: match an order number.
  3. Third unchanged search: match a customer's phone number.

Use batches only when repeated searches are understandable from the displayed results. If users need to control the meaning explicitly, provide separate input fields instead.

You can also use one criterion that unions alternative matches. This example matches either first name or last name beginning with the entered string:

Person.allinstances->select(a|a.FirstName.SqlLike(vSeekString+'%'))->union(
  Person.allinstances->select(a|a.LastName.SqlLike(vSeekString+'%'))
)

Choose the design based on what users can understand and test it with the intended users. A small number of inputs is often easier to use than several narrowly named fields, but the criteria must still make the search meaning clear.

Search dates with DateTime variables

Do not pass dates as text when filtering dates. Database date formats vary, so declare the search variable as DateTime and compare date values.

For example, declare vAfterDate:DateTime and use:

Person.allInstances->select(p|p.Registrered>=vAfterDate)->orderBy(p|p.Registrered)

This returns Person objects registered on or after the supplied date and orders them by the Registrered attribute.

You can set a date limit without displaying it to the user. Set the variable before calling the ViewModel search operation from the search button action:

vAfterDate:=DateTime.Today.addMonths(-6);
selfVM.Search

In this example, the search is limited to objects registered during the previous six months.

Limit the result set

Use the MaxFetch tagged value to control how many records the seeker shows before the user is asked to extend the search. This protects users and the application from unexpectedly large result sets.

Use a restrictive criterion together with MaxFetch. For example, require a name prefix or department selection before returning records from a large Person table. For paging behavior, see the SeekMore logic and Search_result_pages guidance in the relevant seeker implementation.

Order seeker results

A seeker may combine criteria with ->intersection, which makes ordering harder to apply consistently. OCL-PS supports orderBy and orderDescending, including ordering by an attribute reached through one link navigation.

To provide a dedicated ordering expression, add a SearchExpression nesting whose name begins with OrderExpression. When seeker logic finds this nesting, it takes the first active criterion there and appends its orderBy or orderDescending part to the combined seeker expression.

For example, use an order expression when the search criteria return Person objects but the results should be ordered by an attribute on one directly related object. Keep the ordering expression separate from the filtering criteria so the filter intersection remains clear.

For a walkthrough of this ordering behavior, see the View Model Editor discussion.

Use a Seeker in a modal selection flow

You can bring up a Seeker as a modal ViewModel when a user must select an object for another form. For example, a Person form can open a Car Seeker to let the user choose a car.

In the ViewModel action that brings up the Seeker:

  1. Set BringUpViewModel to the Seeker ViewModel.
  2. Select Is Modal.
  3. Set the modal OK-button enable expression so the user can confirm only after a result is selected. The Bootcamp example uses:
vSeekerResult->notempty

See Training:Bootcamp:Chapter 6 for the complete modal-picker exercise.

Design and testing checklist

Before you publish a Seeker, verify the following:

  • Every optional criterion has an Active Expression that prevents it from filtering on an empty or invalid input.
  • Every active criterion returns the same object type as vSeekerResult.
  • A combined search returns the intersection users expect.
  • Repeated unchanged searches produce understandable batch behavior, if you use multiple batches.
  • Date inputs use DateTime variables rather than text.
  • Large-result searches use MaxFetch and a clear way for users to narrow or extend the search.
  • Result ordering is explicit when users need a predictable order.
  • Modal seekers do not enable confirmation until a valid result is selected.

See also

Seeker result paging

Seeker result paging

A multi-variable Seeker can return paging information when a search result does not fit within the MaxFetch setting. MaxFetch controls the maximum number of records returned; when it is not used, the documented default is 20 records.

When paging is enabled, the search first obtains the total hit count and assigns it to vSeekerResultCount. Set the desired page length in vSeekerPageLength. The page count is calculated as vSeekerResultCount/vSeekerPageLength, and vSeekerPage selects the page to fetch.

To identify the grid that displays Seeker search results, add the tagged value IsSeekerResultGrid=true to the grid nesting. The documented paging UI is available in the WPF client and Angular Turnkey client.

See also