Some of the early adopters of VFP 8 have contributed tips for some of the new features of this exciting release.
Check out their ideas, then jump into the product and try some of the new stuff. You'll find that there is much more than meets the eye, with hundreds of additions, changes, and improvements.
Using Schemas with CursorAdapter
Chin Bae
Objective Micro Technologies, Inc.
Have you ever wanted to force a particular column of a query result set to be a specific data type? In prior versions of VFP, one of the few tricks that you can use is to wrap a PADR() around a character expression to force it to be certain length. Also, you could add $0 to any numeric expression to force a numeric column to be a currency data type.
However, there is no simple trick that allows you to cast a numeric expression as integer or force a character expression to be a memo field.
With the CursorAdapter class, you no longer need to use any tricks. The CursorAdapter class has a CursorSchema property that allows you to specify the schema of the result set. Although the CursorSchema was intended to be used against remote data that might not have the exact data types as native VFP data types, this property can be used for queries against native VFP tables, as well.
Besides the ability to cast numeric values as any other data type (integer, currency, double, etc.), CursorSchema allows you to cast virtually any data type as a character type. The example in Listing 1 demonstrates most of the data transformations that are possible.
Several Ways to Start the Environment Manager
Ryan Katri
Although the Environment Manager is normally accessed through the Task Pane Manager, there are other ways to use use it.
To have the Environment Manager easily accessible whether the Task Pane Manager is running or not, it can be added to your Tools menu. To do this, run the Environment Manager application using a command-line option:
DO (HOME() + "envmgr.app") with "-m"
You can also invoke specific environment sets programmatically via command-line options by simply passing the name of the environment set. For example, if the set is named "Toolbox", you would issue the following command:
DO (HOME() + "envmgr.app") with "Toolbox"
Although the environment set name is not case-sensitive, the full name of the set must be specified.
By default, the Environment Manager will always display a message box when an environment is set. To run it quietly, which is sometimes preferred when an environment is set programmatically (such as via a project hook), add a parameter of .T. to the command-line:
DO (HOME() + "envmgr.app") with "Toolbox", .T.
Filtered Index Tag WorksOn a Candidate Index
Mike Yaeger
Siriusware, Inc.
SCENARIO: I have an application that started life in Foxpro 2.0 that keeps track of members of an organization. A requirement of the system is that hand generated membership numbers have to be unique in the system to insure that the wrong member isn't credited with some activity.
THE 2.0 WAY: We used fairly complex code in the VALID clause of the GET statements for this field to save the current controlling index and record number, set the controlling index tag to the membercard column, do a seek on the current value of membercard, then and set the index tag and record pointer back to their original states. In the case of the user editing an existing record, we also had to make sure that we didn't find the record we were working on by mistake. If we missed a place in our app and didn't do this checking, duplicate membercard numbers could be assigned.
THE 3.0 WAY: Primary and candidate index tags were a new tool to prevent duplicates at the database level in 3.0. If every member had a number assigned, it would have been easy to create a candidate index on the membercard column to prevent duplicates, but that's not how the system worked. We did however, change the environment saving and seeking code to a select statement to make the process easier.
THE 8.0 WAY: Now that we can use a filtered index tag for a candidate index, the problem becomes trivial. Create a filtered index on the membercard column and set the index as a candidate index.
CREATE TABLE memberships (membercard I)
INDEX ON membercard TAG membercard FOR ;
membercard<>0 CANDIDATE
INSERT INTO memberships VALUES (0)
INSERT INTO memberships VALUES (14)
INSERT INTO memberships VALUES (0)
INSERT INTO memberships VALUES (0)
INSERT INTO memberships VALUES (14)
As you can see, you can insert as many empty values into the table as you want, but if you do supply a value, it must be unique.