Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.
These two classes are members of the Data environment. Cursor represents an individual table or view (but we’ll say only “table” below unless something is relevant only to views) that’s been added to the DE. Relation contains information about a relation between two cursors in the DE.
Each time you add a table to the Data environment, a new Cursor object is added. It points to the table and lets you set properties (like Alias and Order) used when the table is opened by the DE, either automatically because AutoOpenTables is .T. or by explicitly calling OpenTables.
When you add a table to the DE and that table has a persistent relation with a table already in the DE, a Relation is added. (If the new table has persistent relations with multiple tables, multiple relation objects are added.) The new relations reflect the structure of the persistent relation—in a one-to-many persistent relation, the “one” side becomes the parent and the “many” side becomes the child. Order is automatically set appropriately in the child (via the Relation’s ChildOrder property, not the Cursor’s Order property).
However, the OneToMany property of the relation is never set to .T. automatically—you have to do that yourself. We originally had mixed feelings about this one. After all, we’ve already told FoxPro it’s a one-to-many relationship. However, we rarely end up setting OneToMany ourselves—it just doesn’t seem that important. Besides, with a grid for the “many” side, you can see all the children for the current parent anyway.
You can also add relations by “drawing” them in the Data environment Designer. Drag from a field of one table to a field or index of another. (If there’s no index for the field you specify on the child side, you’re prompted to let Visual FoxPro create it for you.) Notice that the technique for setting up relations in the DE is different than in the Database Designer. That’s because the relations here are temporary relations (the SET RELATION
TO kind), not persistent relations.
Property |
Value |
Purpose |
Alias |
Character |
The alias to use for this table or view in the form. |
BufferModeOverride |
Numeric |
Indicates the type of buffering to use for this cursor. |
CursorSource |
Character |
The name of the table or view the cursor is based on. For free tables, includes the full path. |
Database |
Character |
The name of the database containing this table or view. |
Exclusive |
Logical |
Indicates whether or not to open the table exclusively. |
Filter |
Character |
The filter expression to apply to the cursor. |
NoDataOnLoad |
Logical |
View only. Indicates whether the data for the view is loaded initially or waits until REQUERY() is executed. |
Order |
Character |
The name of a tag to apply to the cursor. |
ReadOnly |
Logical |
Determines whether the table or view is opened in read-only mode. |
Property |
Value |
Purpose |
ChildAlias |
Character |
The alias for the child cursor (the INTO part of SET RELATION). |
ChildOrder |
Character |
The tag used to order the child so the relation can be applied. Should correspond to RelationalExpr. |
OneToMany |
Logical |
Determines whether a one-to-many relation is established. |
ParentAlias |
Character |
The alias for the parent cursor. |
RelationalExpr |
Character |
The expression to use to set the relation. Equivalent to the "TO" clause of SET RELATION. |
Only the Filter and Order properties of cursors (and the Name, Comment and Tag properties of both cursors and relations) can be changed at runtime with equanimity. To change any other property of a cursor or relation, you should first use CloseTables to CLOSE ALL
the tables in the DE. Then, make your changes and call OpenTables to reopen the tables with the new settings. If you change things without closing the tables first, you get an error message and the change isn’t effective until you CloseTables and OpenTables anyway.
Like other contained classes, these can be subclassed only in code. There’s no way, though, to get the Data Environment Designer to use your subclasses.
* You'll normally set this stuff only in the Properties Sheet
* In fact, most of it happens automatically. Here are some
* items you might actually set.
* Assume the PropSheet is pointing at a cursor for Employee.
Filter = "NOT EMPTY(Sales_Region)"
Order = "Last_Name"
* At runtime, you might:
ThisForm.DataEnvironment.Cursor1.Order = "Name"
Alias, BufferMode, BufferModeOverride, ChildAlias, ChildOrder, CursorSource, Database, DataEnvironment, Exclusive, Filter, NoDataOnLoad, OneToMany, Order, ParentAlias, ReadOnly, RelationalExpr, Set Relation