To get anything done you need to find things. The normal software system has the same need. So how do we go about to declare a non-limiting multi variable user friendly seeker into a generic model driven system like the ones we build with MDriven?
This is what we need:
1. We need unrooted (as in not having anything to start with), persistent storage evaluated OCL expressions in order to execute a search
2. We need user input on how to limit the search
3. We need to allow for the user to use different limiting criteria’s as he or she see fit ; after all the One-Field-Matches-Everything tactic that Google use does not really cut the mustard in enterprise applications. Users will want to limit the search on “Only this department”, “Only things from yesterday” etc, and even in google you need to use an extended syntax to get this done
4. We want to allow for multiple sets of search definitions per seeker interface – if the user does not get a hit using the filters with the first set, it is natural for the user to “try again” and then we want to use another set of search criteria’s; this has been tested on real users and many find it intuitive and obvious that it should work this way
Consider this model:
And this is how we can define a seeker:
#1 We declare variables that holds the user input – one variable is a string, and the other is an Object reference of type ReferenceClass (from our model).
#2 We add Columns that use these variables so that we get some UI for the user to enter the criteria’s into. The Reference value we set up as a PickList. We create a SearchExpression - right click menu on view model column - Add nested – Add search expr. When adding the first search expression to viewmodel the designer will also add the default implementation details with a vSeekerResult variable and a SeekString. This is intended as a help and there is nothing magical about the added widgets. The only important thing in a seeker is that there is a variable named vSeekerResult and that it is of type collection
#3 Add two criterias – the result of the two criteria’s will be intersected (on the server side). And here is an important fact: Since the result of the criteria’s will be intersected we need some way to say if a criteria is Active or not – after all it is up to the user to limit the search on either or both of the two criteria’s
This is how the activation of a Criteria is done:
The Active Expression is optional, if you leave it blank it defaults to true – always on
#4 The second batch of search expression is executed the second time the user clicks the search button BUT only if the search variables has not changed. You can have as many search batches as you need, and they are round-robin-used whenever the user clicks the search button with untouched variables. Whenever a variable is changed the Round-robin is reset and the first batch is used again.
Even if these rules may seem complex they are intuitive for the user – especially if you use the search batches to filter for the same data as the resulting columns show. For example; the user enters someone’s first name, but your first batch filter on last name – the wrong people comes up for the first search, the user hits search again – now we use the second batch where you filter on first name – voila. This was just an example – you can just as well create a filter expression that unions the first name and the last name results
Another example might be that the users enters a number – first we try to match it with a product code, user hits search again, we try to match it with the order number. The user is still not happy so he hit search again – now we match it with the phone number of the customer – user happy. In this example we could have chosen to create a detailed search interface with 3 text boxes – one for product code, one for order number and one for customer phone number – just as valid. Or we could do a union expression as above – just as valid. Choose the strategy that sits best with your users. But I urge to you to test the simple interface with a single or only few input boxes - it is user friendly.
Databases use SQL
The search expressions for ocl criterias are different than other than viewmodel column expressions in one important aspect. They are executed against persistent storage (your database). If your database is an SQL-Server these expressions will be translated to SQL and sent to the database for evaluation and execution. The database is much better and faster to handle huge volumes of data than MDriven. This means that we are now able to filter out specific objects in our model from a nearly unlimited sized database. The multi variable seekers described in this chapter will be the natural starting point for your users work in your system. They search – they find – and then they work. The work part is often rooted in a specific found object where your other viewmodels expand the neighboring information.
Useful search examples
Dates are a little tricky because SQL-servers encode dates in many formats. We need to pass dates to search for, not as text, but as values of the date type.
So, when filtering on dates, use variables of the type DateTime.
Here we've created a variable vAfterDate and then are using it to search.
This will find all Persons registrered after the given date and order them on the registrered date.
Need to filter on dates without user seeing it? (to limit search result maybe?), set the DateTime variable before selfVM.Search on the search button like this
vAfterDate:= DateTime.Today.addMonths(-6); selfVM.Search
Limiting the number of results
By adding the tagged value MaxFetch, you can change the number of records shown before asking the user to extend their search.
What type is Searched - what type is vSeekerResult
The vSeekerResult will be created for you as collection of RootType of the ViewModel. If you want another type of vSeekerResult you can declare the vSeekerResult as Collection(YourDesiredType) and then seeker logic will assume search type is YourDesiredType.