Session E-DBCX

Extending The Visual FoxPro
Database Container

Mike Feltman
Neon Software


Introduction

For years, FoxBase and FoxPro developers have realized the need for a central storage location for information about the tables used in our application, or in other words, the need for a data dictionary. For years, FoxBase and FoxPro have lost points in countless reviews because of the lack of this feature. For years the third party market has been flooded with many viable solutions to this problem. Products like Tom Rettig’s Office, Stonefield Data Dictionary, Foxfire! and FoxExpress, that have been available since FoxPro 2.0 or earlier, all are either specifically a data dictionary or gain much of their functionality simply from the mere existence of a data dictionary in the product. Finally, with the release of Visual FoxPro, Microsoft has shown us that they too have recognized this need and thus they’ve given us the Visual FoxPro Database Container.

The Database Container (DBC) is one of the most wonderful new features of Visual FoxPro. The DBC provides us with a convenient location for storing business rules, views and other information that governs the use of data within our applications. Most importantly, because the DBC is a native piece of FoxPro, it provides something that only Microsoft can provide, ties directly to the our business rules at the engine level. Before Visual FoxPro, even the most powerful and sophisticated data dictionaries for FoxPro could only insure the integrity of your data from within an application and even then, the application had to have hard coded references to the data dictionary to accomplish this.

As wonderful as the DBC is, it still leaves much to be desired, and it is not a data dictionary. Although the DBC provides many features in a more elegant fashion than a third party product could possibly provide, in many areas it doesn’t even begin to approach the functionality offered by some of its third party predecessors. What the DBC does provide is a starting point for Data Dictionary features and a logical location for the integration of these features with the FoxPro environment.

What is a Data Dictionary?

The definition of a data dictionary is a system for defining and managing data elements, or fields in an organized manner. It acts as a centralized repository used for storing information about each data element used in a system. The purpose of a data dictionary is to manage table access and also manage what is commonly referred to as 'metadata,' or, data about data.

One of the key requirements of a data dictionary is that it contains all of the information necessary to create the tables it contains. FoxPro’s DBC does not contain field lengths or types or index expressions and other properties that are necessary to create or recreate the tables and associated indexes in a DBC. For this reason, the DBC cannot be considered a data dictionary.

Why are Data Dictionaries Important?

Data dictionaries are important for many reasons. First of all, a data dictionary makes it much easier and much more reliable for a developer to ensure that accurate data is written to the tables used by an application. It’s difficult to even imagine what it would be like to develop a large scale application with complex business rules without a data dictionary. Although, the DBC is not a data dictionary it is a tremendous aid in these areas.

Data dictionaries are also important for many reasons that FoxPro’s DBC does not address. Data dictionaries provide a central place documenting and reporting on the structures of the tables used by an application and the relationships between those files. The structural information stored in a data dictionary is also very useful for various table maintenance functions such as table creation, table repair and rebuilding indexes.

The existence of a data dictionary also makes Rapid Application Development a great deal easier. Whether you use third party tools or create your own, it’s a lot easier to get information about tables, relationships, indexes and fields from one central location than it is to collect this information directly from their sources.

Depending on the sophistication of a data dictionary, the benefits of them can be virtually limitless.

Extending the Database Container

Now that we realize the importance of a data dictionary, we need an approach for implementing one. Because Visual FoxPro has the data base container, and because the data base container contains much of the functionality we desire in a data dictionary, it doesn’t make sense to start from scratch. By adding additional properties and functionality to the database container, we can transform it into a fully functional data dictionary without giving up any of its existing functionality.

What’s in the DBC?

Before we talk about how to go about extending the DBC, it’s important the we first take a glance at what is already there. The DBC is simply a normal FoxPro table. The table below lists the structure of the DBC.
Field Field Name Type Width
1 OBJECTID Integer 4
2 PARENTID Integer 4
3 OBJECTTYPE Character 10
4 OBJECTNAME Character 128
5

PROPERTY

Memo (binary) 4
6 CODE

Memo (binary)

4
7 RIINFO Character 6
8 USER Memo 4

The Object Id field simply store an integer which is used an a unique id for each record contained in the DBC. Unfortunately, when a table’s structure is modified, all of the records associated with the table in the DBC are deleted and new records, with new id’s are added to the DBC.

The Parent Id field is also an integer. It’s value reflects the parent of the current record in the DBC. For example, the parentid of a field is the objectid of the table the field is contained in.

The Object Type field indicates what type of object the current record holds information about. Possible object types include: Connection, Database, Field, Relationship, Table and View.

The Object Name field stores the name of a database, field, relationship, table or view. For fields, the name corresponds with the field name itself. Visual FoxPro automatically names relationships sequentially, the first relationship for each table is called Relation 1 and the second is called Relation 2 and so on. The Object Names for tables default to the physical file name of the actual table but can be edited once the table is loaded into the DBC. The object names for indexes correspond to their tag names.

The Property field is used to store the values of various properties, like captions, error messages and valid expressions, that can be set in the DBC.

The Code field is used to store procedures directly into the data base container.

The RIInfo field store information that is used by the RI Builder to generate stored procedures for relational integrity.

By default, no information is stored in the user memo field and this field can be used to store additional information in any manner we see fit.

What’s not in the DBC?

For the purposes of this session, because this session is about extending the DBC, we are more concerned with what’s not in the DBC than with what is in the DBC. We’ve already talked about the lack of structural information in the DBC, but other items that would aid in application development are also not stored in the DBC. For example, wouldn’t it be easier if the tool tip text for each field in your application was stored in the DBC and the objects on your forms automatically retrieved the tool tip text at run time instead of typing the tool tip text into each object on a form? What about input and output masks or report headings? All of these items could easily be stored in the DBC, or an extension of it, and simply entered once, in one central location as we develop our applications, rather than over and over again each time we encounter the need for them.

How to Extend the DBC?

Now that we’ve talked about what’s in the DBC and additional information that we’d like to see in the DBC, we need to figure out exactly where to store this information. There are many viable approaches to this and it seems as though all of them are in use somewhere.

There are basically three approaches you can take to extend the DBC. All of the approaches I’m familiar with are a variation of one of these approaches.

  1. Modify the structure of the DBC to include additional fields
  2. Store additional information in the user memo field of the DBC
  3. Store additional information in a separate table.

Adding Fields to the DBC

The first and most obvious approach is to simply add fields directly to the DBC. You can add fields to the DBC by using the DBC as a table and issuing a MODIFY STRUCTURE command. You can also add index tags to the DBC, but the indices are not stored in the DCX, (DCX is the extension given to the files that holds the index tags that FoxPro automatically attaches to the DBC.)

While this approach is the most obvious, it’s probably the poorest solution for several reasons.

  1. If the DBC becomes corrupt, you’ll not only lose the DBC, you’ll also lose your extensions.
  2. If a new version of Visual FoxPro is released with DBC enhancements, what will Microsoft do to your additional fields when you open the DBC in the new version?
  3. You cannot add records to the DBC. The inability to add records to the DBC means that using the approach of adding fields to the DBC can be very limiting. What if you want to store information that does not directly pertain to a table, view, field, index or relationship already stored in the DBC?
  4. The DBC already has 8 fields in it and because Visual FoxPro still has a limit of 255 fields per table, you have a limited number of extensions you can add.

For these reasons, adding fields to the DBC is probably not a very good approach to extending the DBC, except in a very limited fashion.

Storing Additional Information in the User Memo of the DBC

Because the user memo of the DBC is a regular FoxPro memo field, the amount of information that can be stored in it is limited only by the amount of disk space on your computers. Storing additional properties in the user memo is another possibility for extending the database container. Before choosing this approach, there are also several disadvantages to consider:

  1. Using this approach you will also be limited by the fact that you may not add records to the DBC.
  2. Furthermore, unless you are storing a very limited amount of information in the user memo, it’s highly likely that you will run into performance problems if your applications need to retrieve information from the user memo, especially for multiple records.
  3. Using this approach also means that you’ll have to write a great deal of code to constantly read and write information from memo fields. Imagine how much code it might take to create a list of the fields in a table, a meaningful prompt for the fields, their data type and their size. Now imagine creating a similar list for multiple related tables. Not only will this take a great deal of code, in all likelihood you will also not be able to get satisfactory performance out of routines of this type.

Storing Additional Information in a Separate Table

The last approach we’ll look at is storing additional information in a separate table or tables. This approach has the disadvantage of the additional overhead of additional tables, but seems the most flexible and safest. In this approach, an id is added to the user memo of the DBC which is used as a pointer to a related record or records in an extension table.

Two public domain database container extensions, EDC by Tom Rettig and DBCX by Flash Creative Management, Micromega Systems and Neon Software that use this approach have been released to the public domain.

EDC and DBCX are very similar in terms of their functionality. Both of these extensions rely on storing an id in the user memo of the DBC and use this id to point to information in separate tables. Both use SetProp and GetProp methods similar to the Visual FoxPro DBSetProp and DBGetProp functions to read and write information from the extension.

Why Two Different Approaches?

It is somewhat unfortunate that two different approaches for extending the DBC have been released to the public domain. It was the hope of all parties involved that the two approaches could eventually involve into a single standard and that may still happen someday. The reality is that all the parties involved had different needs, different priorities, different agendas and different starting points and eventually both approaches got far enough along that putting them together became impractical.

What’s the Difference?

The primary difference between the two DBC extensions is that DBCX was designed to specifically to support multiple extensions and by default actually has no extensions (although the Codebook extensions are distributed with it and are also public domain), whereas EDC was designed to support a specific extensions and by default includes that set of extensions. Although EDC was primarily designed to deal with a single extension set, it has the capability of supporting multiple extensions. Therefore, although no one has written anything to accomplish this, it is possible to use EDC to manage DBCX extensions or DBCX to manage EDC extensions and use the best of both worlds.

Currently, the scope of EDC, and the goals is also much broader than that of DBCX’s. Whereas DBCX deals exclusively with tables, EDC will eventually contain methods for reading and writing properties of other FoxPro file types.

As of this writing, EDC will be used by Tom Rettig’s Office products and any other products released by Rettig Micro Corporation. Although there are probably other vendors planning on using EDC, I don’t know of any. On the other hand, DBCX was developed jointly by Flash, Micromega and Neon. Each of these vendors will use DBCX in their products. In addition, Stonefield Systems, Cascade Interactive Designs, SBT, The Elk, RESolutions, Performance Dynamics, Hentzenwerke, Korenthal Associates and several other vendors have signed on to be compatible with Codebook and DBCX. In other words, which set of DBC extensions you choose to use, may simply be a function of what third party products, if any, you use.

As of this writing, there is one other important factor to keep in mind when choosing a set of database container extensions. By themselves, neither DBCX or EDC really does anything. To make use of EDC or DBCX you really need a set of classes or other application components that make use of them. Simply setting properties in a database container extension doesn’t tell your application to make use of them.

Inside DBCX

For the remainder of this session, we’ll focus on DBCX. Remember, my intent here is to talk about extending the DBC and the advantages of doing so. We’re looking at DBCX primarily because I’m much more familiar with it than EDC, but everything I cover in the remainder of this session could also be accomplished in a similar fashion using EDC.

What Exactly is DBCX?

DBCX allows multiple products to enhance the DBC without "stepping on each other’s toes". It allows each developer to decide where and how the extended attributes will be stored, by making extensive use of Visual FoxPro’s object oriented capabilities and polymorphism.

At the same time, it has become apparent that many common attributes are handled by each third party product. A common subset of these attributes are included with this document, and will be used in The Visual FoxPro 3 Codebook.

Essentially, DBCX is a manager class. The manager class manages database container extensions. Each extension is also a manager class. Their purpose is to read and write database container extended properties.

The Registry Table

Central to DBCX functionality is a FoxPro table called the registry table. This table tells DBCX, among other things, the tables that are being used as DBC Extensions and the objects used to manage those tables. The registry table must be named DBCXREG.DBF. You can have as many of these as you need, but can only point to one within any given project. At Runtime, this table must be somewhere in your path, or "included" in your APP/EXE.

Table Structure

A description of the DBCXREG.DBF file follows:
Field Purpose
mDbcPath The path to a database container that may be used by the extension manager.
cDbcName The name of the database container if one is used by the extension manager.
cProdName The name of the registered product.
cVersion The version number of the registered product.
mDbcxPath The path to the product extension file.
cDbcxName The name of the product extension file.
cDbcxAlias The Alias name to be used when the product extension table is opened.
mLibPath The path to the product specific extension manager class library.
cLibName The name of the product specific extension manager class library. This may be .VCX or .PRG.
cClassName The name of the class object for use when the object is instantiated (CREATEOBJECT).
iLastId The last id used in the database container.
tLastUpdt The entry was made (DateTime).

There is one index on DBCXREG.DBF:
Tag Name Index Expression Type
cProdName UPPER(cProdName) Candidate

Each registry table must have a record where the cProdName is SYSTEM RECORD. This is the only record that uses the iLastId field. The system record holds the last id used in the database container and is used to generate the next available id.

Example of DBCx Registry

Field Name Record #1 Record #2 Record #3 Record #4
mDbcPath   Cdbk30\    
cDbcName   CdbkMgr.Dbc    
cProdName SYSTEM RECORD CodeBook FoxExpress Foxfire!
cVersion   V3.2 V3.0 V3.01
mDBCXPath   MetaData\ MetaData\ MetaData\
cDBCXName   CdbkMeta.Dbf FeMeta.Dbf FfMeta.Dbf
cDBCXAlias   CodeBook FoxExpress Foxfire
mLibPath   libs\ fe\ ff\
cLibName   CdbkMgr.vcx FeMgr.vcx FfMgr.vcx
cClassName   CdbkMgr FeMgr FfMgr
iLastId 0      
tLastUpdt 09/22/95 11:29:34 AM 08/22/95
11:29:34 AM
08/22/95
11:29:34 AM
08/22/95
11:29:34 AM

The DBCX Manager Class

The name of the DBCX Manager Class is METAMGR which is located in DBCXMGR.VCX. Issuing a CREATEOBJECT() instantiates the DBCX Manager class. It then looks for DBCXREG.DBF, and creates members objects that point to each installed 3rd Party class. It compiles a list of properties from each of the classes and waits for any requests from the applications that are in use.

To create an object based on the DBCX Manager class in an application, you would issue commands similar to the following:

SET CLASSLIB TO DBCXMGR ADDITIVE
PUBLIC oMetaMgr
oMetaMgr=CREATEOBJECT(„MetaMgr")
IF TYPE("oMetaMgr")<>"O"
=MESSAGEBOX("Error creating data base container extension manager. Object not created.",MB_ICONEXCLAMATION)
ENDIF

When the oMetaMgr is created, the registry table is read, each of the objects listed in the registry table are created and each of the tables associated with an extension are opened. Now your application is ready to take advantage of DBCX.

Now What?

Well, now that you’ve got the meta manager instantiated, what do you do with it? By itself, DBCX really doesn’t do much of anything. Remember, DBCX is basically just a programmatic interface to either vendor supplied extensions or extensions you’ve created yourself. Because the Codebook extension is public domain, we’ll spend the rest of this session looking at some practical examples of DBCX in use.

Sample Uses of DBCX

Overview

DBCX, as it is distributed is included on the conference diskettes. I’ve also included a small FoxPro project called DBCXDEMO. DBCXDemo includes several important example uses of DBCX. To run DBCXDemo, simply set default or change directory to the sample directory and issue the command DO DBCXDemo from the Command Window.

What’s in DBCXDemo?

DBXDemo.Prg

Several important concepts and usage’s of DBCX and the Codebook extensions are in DBCX demo. First, the main program, DBCXDemo illustrates how to instantiate the meta manager object. It also calls a program called DBCXLoad if there are no records in the Codebook extension. DBCXLoad calls the AddRow method of each extension to load data into the extensions.

EditDBCX.SCX

The form EditDBCX illustrates how to use two methods of DBCX. First, it uses the DBGetDBCKey method of DBCX to find the DBCX Id of an item in a database container. Remember, all of the information stored in any Database Container Extension is tied to a unique id. In order to access information in a Database Container Extension, it’s necessary to find it’s id.

Next, after the id has been found, the Show method of oMetaMgr is called to allow the user to open a the default DBCXShow Form. The Show form allows you to view the properties contained in database container extensions as well as set properties. The Show Method is used to maintain items in a database container extension.

DBCXForm

DBCXForm is a sample form that takes advantage of DBCX by getting property values, such as tooltip text, input masks and captions, associated with the forms objects from the Codebook Database Container Extension. This form uses objects from the DBCXSmpl Class Library, which we’ll examine in detail.