Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

When a user types a value into a text field (which is bound to a specific column of the database table) and clicks out, the Servoy Application Server issues a SQL update command to the database to modify the selected record. The resulting change is also broadcast|display/DOCS/Data+Broadcasting|||||\ to all connected clients.

...

The fundamental unit of data binding in both the GUI and the API is the Servoy Foundset|display/DOCS/Foundsets+Concepts|||||\ object.

Client Cache

A Servoy client instance keeps track of which database records are in use. This is called the Client Cache and it optimizes performance by reducing the number of queries made to the database. Records are tracked by primary key. The first time the contents of a record are accessed, the Application Server must issue a query to the database on behalf of the client. The values for all of the columns of the record object are held in memory and therefore, subsequent access of the record will not produce anymore queries to the database. The user experience is greatly enhanced as one can browse quickly between forms and among cached records.
A record may fall out of the cache gracefully to conserve memory and is automatically reloaded the next time it is accessed. This happens at the discretion of the client's caching engine, which is highly optimized. Relieved of the burden of managing memory, the developer can focus on more important things.

...

A Foundset may be automatically updated when the client receives a Data Broadcast Event. If the data change affected the table to which the foundset is bound, the foundset will be refreshed to reflect the change.

Find Mode is a special mode that can be assumed by a foundset object to perform data searches using a powerful, high-level abstraction. When in Find Mode, the foundset's Data Providers, normally used to read/write data, are instead used to enter search criteria. Any data provider can be assigned a search condition which should evaluate to a String, Number or Date. Because forms typically bind to a foundset, criteria may be entered from the GUI by the user or programmatically.

A foundset enters Find Mode when its find method is invoked. This method returns a Boolean, because under certain circumstances, the foundset may fail to enter find mode. Therefore, it is good practice to enclose a find in an an if statement, so as not to accidentally modify the selected record. A foundset exits Find Mode when its search method is executed, upon which the foundset's SQL query is modified to reflect the expressed criteria and the matching records are loaded. The search method returns an integer, which is the number of records loaded by the find. However this doesn't necessarily represent the total number of matching records as foundset records are loaded in blocks.

Example:

Code Block

// Find all customers in the city of Berlin
if(foundset.find()){   // Enter find mode
    city = 'Berlin';   // Assign a search criteria
    foundset.search(); // Execute the query and load the records
}

Results in the foundset's SQL query:

Code Block

 SELECT customerid FROM customers WHERE city = ? ORDER BY customerid ASC

...

Search Criteria with Logical AND

...

When multiple search criteria are entered for multiple data providers, the criteria will be concatenated with a SQL AND operator.

Example:

Code Block

// Find all customers in the city of Berlin AND in the postal code 12209
if(foundset.find()){     // Enter find mode    city = 'Berlin';     // Assign city search criterion
    postalcode = '12209' // Assign postal code criterion
    foundset.search();   // Execute the query and load the records
}

Results in the foundset's SQL query:

Code Block

 SELECT customerid FROM customers WHERE city = ?  AND postalcode = ? ORDER BY customerid ASC

...

Multiple Find Records for Logical OR

...

It's important to note that when in Find Mode, a foundset will initially contain one record object. However, multiple record objects may be used to articulate search criteria. This has the effect that the criteria described in each record are concatenated by a SQL OR.

Example:

Code Block

// Find customers in the city of Berlin AND in the postal code 12209...
// OR customers in the city of San Francisco AND in the postal code 94117
if(foundset.find()){        // Enter find mode    city = 'Berlin';     
    postalcode = '12209';
    foundset.newRecord();   // Create a new search record
    city = 'San Francisco'
    postalcode = '94117';
    foundset.search();      // Execute the query and load the records
}

Results in the foundset's SQL query:

Code Block

 SELECT customerid FROM customers WHERE (city = ?  AND postalcode = ?) OR (city = ?  AND postalcode = ?) ORDER BY customerid ASC

...

Finding records through a relation

...

Find Mode is very flexible as searches can traverse the entire data model. When a foundset enters find mode, any foundset related to a search record can be used to enter criteria. Moreover, related foundsets can use multiple search records so any permutation of Logical AND / OR is possible.

Example:

Code Block

// Find customers that have 1 or more orders which were shipped to Argentina
if(foundset.find()){                               // Enter find mode
    customers_to_orders.shipcountry = 'Argentina'; // enter criteria in a related foundset
    foundset.search();                             // Execute the query and load the records
}

Results in the foundset's SQL query:

Code Block

SELECT DISTINCT customers.customerid FROM customers
LEFT OUTER JOIN orders ON customers.customerid=orders.customerid
WHERE orders.shipcountry = ? ORDER BY customers.customerid ASC

And there are no limitations to the number of traversals across related foundsets.

Example:

Code Block

// Find customers with one or more orders containing one or more products supplied by a vendor in USA
if(foundset.find()){
    customers_to_orders.orders_to_order_details.order_details_to_products.products_to_suppliers.country = 'USA';
    foundset.search();
}

...

Finding records within a related foundset

...

It is worth pointing out that related foundsets may be put into Find Mode as well. The foundset will maintain the constraints imposed by the relation in addition to the criteria specified in the data providers.

Example: This operation is nearly identical to the previous search on ship country, however it matters which foundset is in Find Mode. The difference is that this operation searches for order records of a particular customer.

Code Block

// Find orders of THE SELECTED CUSTOMER that were shipped to Argentina
if(customers_to_orders.find()){
    customers_to_orders.shipcountry = 'Argentina';
    customers_to_orders.search();
}

Results in the foundset's SQL query (notice the relation constraint is preserved):

Code Block

SELECT orderid FROM orders  WHERE customerid = ? AND shipcountry = ? ORDER BY orderid ASC

...

Special Operators

...

Servoy's Find Mode provides several special operators that when used in combination can articulate the most sophisticated search requirements.  Operators and operands should be concatenated as strings.

Operator

Description

Applicable Data Types

Example

||

OR: Used to implement a logical OR for two or more search conditions in the same data provider

Any

Code Block

 // Cities of London or Berlin
city = 'Berlin||London';

|

Format: Used to separate a value and an implied format.

Date

Code Block

 // exactly 01/01/2001 (00:00:00 implied)
orderdate = '01/01/2001|MM/dd/yyyy'

!

Not: Used to implement a logical NOT for a search condition.

Any

Code Block

// Anything but Berlin
city = '!Berlin';

#

Sensitivity Modifier: Implies a case-insensitive search for text columns. Implies a match on entire day for date columns.

Text, Date

Code Block

// i.e. Los Angeles, lOS aNGeLES
city = '#los angeles';

// any time on 01/01/2001
orderdate = '#01/01/2001|MM/dd/yyyy';

^

Is Null: Matches records where a column is not null.

Any

Code Block

// All null contact names, not including empty strings
contactname = '^';

^=

Is Null/Empty/Zero: Matches records where a column is null, empty string value or zero numeric value

Text, Numeric

Code Block

// All freights which are null or 0
freight = '^=';

<

Less than: Matches records where the column is less than the operand

Any

Code Block

// i.e. 50, 99.99, but not 100, 101
freight < 100;

<=

Less than or equal to: Matches records where the column is less than or equals the operand

Any

Code Block

// i.e. Atlanta, Baghdad, Berlin, but not Buenos Aires, Cairo
city <= 'Berlin';

>=

Greater than or equal to: Matches records where the column is greater than or equals the operand

Any

Code Block

// Any time on/after 12am new year's day 2001
orderdate '>=01/01/2001|MM/dd/yyyy';

>

Greater than: Matches records where the column is greater than the operand

Any

Code Block

// i.e. 100.01, 200, but not 99,100
freight > 100;

...

Between: Matches records where the column is between (inclusive) the left and right operands.

Any

Code Block

// Any time during the year 2001
orderdate = '01/01/2001...01/01/2002|MM/dd/yyyy';

// i.e.
frieght = 100...200

// i.e. London, Lyon, Madrid, Omaha, Portland
city = 'London...Portland'

%

Wild Card String: Matches records based on matching characters and wild cards

Text

Code Block

city= 'New%';    // Starts with: i.e. New York, New Orleans
city = '%Villa%; // Contains: i.e. Villa Nova, La Villa Linda
city = '%s';     // Ends with: i.e. Athens, Los Angeles

_

Wild Card Character: Matches records based on

Text

Code Block

// i.e. Toledo, Torino
city = '%To___o%';

\

Escape Character: Used to escape other string operators

Text

Code Block

// Escape the wild card, i.e. ...50% of Capacity...
notes = '%\%%';

now

Now: Matches records where the condition is right now, including time

Date

Code Block

// exact match on this second
creationdate = 'now';

today

Today: Matches records where the condition is any time today

Date

Code Block

// match on anytime today
orderdate = 'today';

...

Complex Searches

...

Servoy's find mode can be used to easily satisfy even complex search requirements. Remember that any related foundset may be used to enter criteria and that any number of search records may be used in any foundset and any operators may be used in combination for every data provider.


Panel
titleQuestion from Patrick Talbot that this chapter could answer

I remember I was thinking that there were some gray areas when it comes to datasets and foundsets, and generally how Servoy is generating the SQL from these depending on relations etc. I noticed that there were often questions about that in the forum, and no definitive answers of course (but at least pointers to what approach gives you what), and in my company too, people are coming to me quite often with some of the following questions:

  1. the 200 records loaded in a batch, and how to treat it correctly
  2. databaseManager.loadRecords() different flavors and what it does exactly
  3. how Servoy is treating DB Views (no refreshing, need to manually add the PK(s))
  4. calculations and aggregations and how/why they will deteriorate performances (what is the SQL involved especially in case of table/list forms)
  5. about dataBroadcast, how they act on foundsets but not datasets (nor foundsets based on views)
  6. dataBroadcast again: how to refresh you client's data after a batch (processor) update (maybe demonstrate the new headless_client plugin?)
  7. how to use the JSFoundsetUpdater properly, and how to efficiently update a whole foundset in one go
  8. the use of databaseManager.setCreateEmptyFormFoundsets() and what it means
  9. the advantage of using valueLists instead of relations to display related data in table/list forms
  10. how/why Servoy is sometimes creating temporary table to perform some joins
  11. generally how to interpret the performance tab in the server admin

Seems like a lot of topics in one, really, but of course not necessarily all of these topics need to be addressed, or addressed at the same time, but I really think that these are things that need more explanations/clarifications/demonstrations.

...