METHOD AND APPARATUS FOR STORING AND RETRIEVING DATA IN A RELATIONAL DATABASE USING AN OBJECT MODEL

Abstract: Disclosed is a design tool (50) including a custom application (51) for creating forms and reports based on objects in an object model in order to store and retrieve data from a relational database (52). The forms also enable queries to be performed on data stored in the relational database. The design tool runs on a computer (62) that includes a processing unit (63) controlled by an operating system (64).

Description: METHOD AND APPARATUS FOR STORING AND RETRIEVING DATA IN A RELATIONAL DATABASE USING AN OBJECT MODEL Field of the Invention The invention is directed toward database management systems and, more specifically, to a method and apparatus for storing and retrieving data in a relational database using an object model. Background of the Invention Since the late 1960's, computer database management systems (DBMSs) have been continually enhanced and improved not only to facilitate the processing of data, but also to incorporate features that allow the automatic creation of database applications. A database application consists of forms, reports, queries, menus, and application programs. Forms, reports and queries are the means though which a user can store and retrieve data in a database. Specifically, a form allows a user to input data into the database; queries are commands that cause a computer to search for data in the database meeting some search criteria; and a report is a listing of data that has been retrieved from the database by a query. Application programs traditionally have included routines that were custom written by database experts based on the requirements of an end user of the database. Application programs are typically either written in a language that is a part of the DBMS or in a standardized command language and syntax, such as structured query language (SQL). For further information regarding SQL, please see A Guide to the SQL Standard, C.J. Date (Addison-Wesley, 2d ed., 1989). A number of desktop database programs that operate on personal computers have become available in recent years. Examples of such desktop database programs include Access™ from Microsoft, Inc., and Paradox™ from Borland, Inc. These programs allow a developer to define the types of information to be stored in a database, and have tools to assist in the creation of forms for users to enter data into the database and print reports that contain previously stored information. Some desktop database programs have the capability of allowing a user to customize the content and look of the forms and reports. In a relational database, data are logically stored in a row of a two- dimensional table having multiple columns to define the particular data that are stored. Traditionally, it has been difficult for users to set up relational database tables, also referred to as a database schema, that accurately mirror the user's idea of how data should be stored. This is because traditional DBMSs force the user to define the data to be stored in a database in a way that is determined by the database program. For example, to create a new database, most DBMSs present the user with a blank table and ask the user to identify the type of data to be placed in each column. If more than one table is required for defining the database schema, the user must also create additional tables appropriate for the data. In addition, the user must also define key fields or attributes that are common to two or more tables in order to relate the tables to one another. A significant disadvantage of traditional methods of creating database applications is that the user most likely does not think of the data to be stored in terms of tables, columns, and keys. For example, the user who wishes to create a database for investment portfolio data most likely thinks of the data in terms of the names of companies in which stock is held, the number of shares of each company owned, a purchase price, a purchase date, a price-to-earnings ratio, etc. By requiring the user to define relational tables in conformance with arbitrary rules, most prior art DBMSs force the user to think of and characterize the data to be stored in a way that is unnatural. Unfortunately, the relational database concepts carry over into the forms and reports that are generated, making these less intuitive to users as well. In response to the difficulties encountered when attempting to create database applications using prior art programs, Wall Data Incorporated, of Redmond, Washington, the assignee of the present invention, continues to develop a database application generating program called SALSA™. Portions of the program were described in U.S. Patent Application Serial No. 08/145,997 (the '997 application), entitled "Object Modeling System for Creating Relational Database Schemas," which is hereby incorporated by reference. Briefly, the SALSA program allows users to create a model of data to be stored in a database using one or more semantic objects. Each semantic object represents a complete item, such as a person, an order, a company, or anything else that a user thinks of in terms of being a unique entity that will be stored in the database. Each semantic object has one or more attributes or "components" that define identifying information about the object, as well as object links that define relationships between the objects in the database model. Once the user has completed the object model, the SALSA computer program analyzes the object model and creates a corresponding relational database schema which can be used to store data in the computer. For additional information regarding the SALSA program, please see Database Processing, Fundamentals, Design and Implementation, D. Kroenke (Prentice Hall, 5th ed., 1995), and Object Modeling With SALSA™, A Tutorial, S. Dewitz and M. Olson (McGraw-Hill, 1994). The Database Processing, Fundamentals, Design and Implementation and Object Modeling With SALSA™, A Tutorial books are hereby incorporated by reference. While Version 1.0 of the SALSA program allows a user to easily create a database schema without knowledge of traditional relational database concepts, it does not provide a means for automatically creating forms and reports that can be used to store and retrieve information from a database. An improved database system that automatically generates forms and reports for accessing data in a database using object modeling concepts would be extremely advantageous. Summary of the Invention The invention is directed to a method of generating forms and reports in order to store and retrieve data from a relational database using an object model. In one aspect of the invention, a method of creating forms based on a semantic object in a semantic object model is described. The method comprises: (a) creating, in response to user input, an object model, the object model including a plurality of semantic objects, each semantic object having one or more components that define the semantic object, and wherein two or more of the semantic objects are further defined by relationships therebetween; (b) automatically generating, in accordance with a set of default rules, one or more object view hierarchies for each semantic object in the object model, the object view hierarchies containing information about an associated semantic object, including the component or components defining the corresponding semantic object and relationships with other semantic objects in the model, if present; (c) generating a form from each object view hierarchy; (d) displaying, in response to user input, a current form that is of interest to the user; and (e) determining if modifications have been made by the user to either the current form or the underlying object view hierarchy upon which it is based, and if modifications have been made, changing the contents of the underlying object view hierarchy or the current form- respectively, to reflect the modifications. In another aspect of the invention, a semantic object in the object model may contains one or more action components, each action component resulting in a command button being created on a form generated from an object view hierarchy associated with the semantic object. An action component enables one the following functions to be invoked by a user of a form: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for a semantic object that is related to the semantic object that contains the action component. A semantic object in the object model may also contain an action group component, consisting of two or more action components, that results in a menu bar being created on a form generated from an object view hierarchy associated with the semantic object. The action group component contained by a semantic object may be used to limit access to data in the relational database by a user of a form associated with the semantic object by providing only selected functions on the menu bar created on the form. In another aspect of the invention, a method of storing data in a relational database using an object model is described. The object model is first translated into a database schema including one or more relational database tables that describe the relational database using techniques disclosed in the '997 application. The method includes: (a) selecting an object from the object model; (b) automatically generating, according to a set of default rules, a form based on the selected object for storing data in the relational database; (c) combining the form with information about the database schema and information about the selected object, including information regarding any relationships that exist between the selected object and other objects in the object model; (d) prompting a user to enter data to be stored in the relational database into the form; and (f) writing the data that has been entered into the form to the relational database. Steps (a)-(c) may be repeated for each object in the object model. In another aspect of the invention, the objects in the object model are semantic objects. In another aspect, a computer-readable memory that can be used to direct a computer to function in the manner specified above when used by a computer is described. In a further aspect of the invention, the step of writing the data that has been entered into the form to the relational database includes: (a) determining if data entered into the form comprises a valid record in accordance with the object model; and (b) if the data that has been entered is not a valid record, displaying an error message without writing the data that has been entered into the form to the relational database. In yet another aspect of the invention, each form is comprised of a collection of fields, each field being associated with either a component in the selected object or a component from an object that has a relationship with the selected object. The fields comprising the form are determined by the set of default rules. A user may change the fields contained in the form from those included by the default rules. In another aspect of the invention, the method includes enabling a user to modify the contents of the form from what is dictated by the default rules. In another aspect, the step of automatically generating a form for storing data in the relational database includes: (a) automatically generating, according to a set of default rules, an object view hierarchy based on the semantic object, the object view hierarchy including information about the components defining the selected object as well as information regarding the relationships, if any, that exist between the selected object and other objects in the object model; and (b) using the object view hierarchy to generate the form. In another aspect of the invention, a user may modify the contents of the form, if desired. Specifically, the step of enabling a user to modify the contents of the form includes: (a) displaying the form; (b) monitoring user inputs relating to the form to determine if the user has made any modifications to the contents of the form, and if modifications have been made, changing the contents of the object view hierarchy associated with the form to reflect the modifications; and (c) automatically generating a new form from the object view hierarchy. In another aspect of the invention, a user may perform queries on data stored in the database using the form. In another aspect, each form includes a plurality of fields, wherein each field is associated with a component in the object model. If a user wishes to can perform queries on data stored in the database using the form, the method includes (a) prompting the user to enter query information into one or more fields of the form; and (b) retrieving data records, if any, that match the query information and displaying those data records. In a further aspect of the invention, the step of writing the data that has been entered into the form to the relational database includes generating SQL statements appropriate for the database from the information about the database schema and information about the selected object. In another aspect of the invention, the step of combining the form with information about the database schema and information about the selected object includes creating a run-time view hierarchy for the form. In another aspect of the invention, each component represents an instance of data stored in the relational database that is represented by the object with which the component is associated, the components including simple value components that represent data entry in a single column of the relational database, group components having one or more member components that represent a logical collection of components, and object link components that represent relationships between the objects in the object model. One or more components are classified as identifier components that are used to choose between instances represented by the same object, and each component has a minimum and maximum cardinality that define the minimum and maximum instances, respectively, allowed for the component. Further, the set of default rules includes adding to the form a control for each simple value component and each group component that defines the selected object, and a control for each identifier component in an object related to the selected object by a nonrecursive object link component. In still further aspects of the invention, an object in the object model contains one or more action components, each action component resulting in a command button being created on a form generated for the object. An action component may be added to enable one the following functions to be invoked by a user of the form: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for a semantic object that is related to the semantic object that contains the action component. An object in the object model may also contain an action group component, consisting of two or more action components, that results in a menu bar being created on a form generated for the object. The action group component contained by an object may used to limit access to data in the relational database by a user of a form associated with the object by providing only selected functions on the menu bar created on the form. In a further aspect of the invention, a method of storing and retrieving data to and from a relational database using an object model includes: (a) creating, in response to user input, an object model comprising one or more objects, each of which represents an item about which data is stored in one or more tables of a relational database; (b) creating, in response to user input, one or more components associated with one or more objects in the object model and representing data stored in the relational database for the item represented by the object with which the component is associated, the components including object link components that represent relationships between objects in the object model; (c) translating the object model into a database schema including one or more relational database tables that describe the relational database; (d) automatically generating, in accordance with a set of default rules, an object view hierarchy for each object in the object model, each object view hierarchy containing information about its associated object, including the component or components defining the object and the object links, if any, between the associated object and other objects in the model; (e) automatically generating, in accordance with a set of default rules, a run-time view hierarchy for each object in the object model by combining information contained in an object's object view hierarchy with information in the database schema; and (f) automatically generating a form from each run-time view hierarchy that may be used to store and retrieve data to and from the relational database. In another aspect of the invention, the method further includes: (a) prompting a user to enter data to be stored in the relational database into a form; and (b) writing the data that has been entered into the form to the relational database. In another aspect of the invention, the method further includes: (a) displaying, in response to user input, a current form that is of interest to the user; (b) prompting the user to enter modifications to the contents of the form; and (c) if modifications have been made to the current form by the user, changing the contents of the object and run time view hierarchies associated with the form to reflect the modifications, and generating a modified form from the run-time view hierarchy. In a still further aspect of the invention, a method of retrieving data records stored in a relational database using an object model is disclosed. The method comprises: (a) automatically generating, according to a set of default rules, a form based on an object in the object model, the form including a plurality of fields, wherein each field is associated with a component in the object model; (b) prompting a user to enter query information into one or more fields of the form; and (c) retrieving data records, if any, that match the query information and displaying those data records. In one aspect, the step of retrieving data records may be accomplished by combining information about the database schema with information about the selected object, including information regarding any relationships that exist between the semantic object and other objects in the object model and using this information to perform the query on the relational database. The step of automatically generating, according to a set of default rules, a form based on an object in the object model may be repeated for each object in the object model. In a still further aspect of the invention, a method of storing data in a relational database using an object model comprises: (a) selecting an object from the object model; (b) automatically generating, according to a set of default rules, an object view hierarchy based on the selected semantic object, the object view hierarchy including information about the components defining the selected semantic object as well as information regarding the relationships, if any, that exist between the selected semantic object and other semantic objects in the object model; (c) automatically generating a form for storing data in the relational database from the object view hierarchy; (d) prompting a user to enter information into the form; and (e) storing data that has been entered into the form into the relational database by combining information about the database schema with information contained in the object view hierarchy. Brief Description of the Drawings The foregoing aspects and many of the attendant advantages of this invention will become more readily appreciated as the same becomes better understood by reference to the following detailed description, when taken in conjunction with the accompanying drawings, wherein: FIGURE 1 A is a block diagram of a database design tool in accordance with the invention, including both design time and run-time aspects of the invention; FIGURE IB is a block diagram of a custom application that is created by the database design tool at run time in accordance with the invention; FIGURE 1C is a block diagram of a computer on which the database design tool may run in accordance with the invention; FIGURE 2A is a computer display screen shot of a graphical user interface illustrating a sample object model in accordance with the invention; FIGURE 2B is the computer display screen shot shown in FIGURE 2A, but including an exemplary component properties window that may be used to alter one or more property values of a semantic object, template, or model component; FIGURE 3 A is an example of a default form generated by the design tool for the semantic object "customer" from the object model in FIGURE 2A in accordance with the invention; FIGURE 3B is an example of a default form generated by the design tool for the semantic object "order" from the object model shown in FIGURE 2A in accordance with the invention; FIGURE 4A is an example of a default report generated by the design tool for the semantic object "customer" in accordance with the invention; FIGURE 4B is an example of a default report generated by the design tool for the semantic object "order" in accordance with the invention; FIGURES 5A-5B illustrate the object model of FIGURE 2A, but where exemplary action item and action group components have been added to the customer semantic object in accordance with the invention; FIGURES 5C-5D illustrate the creation of a windows button and a menu bar on the form of FIGURE 3A in accordance with the invention, resulting from the action item and action group components that were added to the customer semantic object; FIGURE 6A is a flow chart of an exemplary routine for implementing the design tool in accordance with the invention; FIGURE 6B is a flow chart of an exemplary routine for constructing forms and reports in accordance with the invention; FIGURE 7 illustrates the class hierarchy for a generic view object in accordance with the invention; FIGURE 8 represents a computer display screen shot of portions of a graphical user interface that includes an exemplary object model for use in describing the invention; FIGURE 9A illustrates the semantic object hierarchy for the semantic object "order" displayed in FIGURE 8; FIGURE 9B and 9C illustrate object view hierarchies for the semantic object "order" displayed in FIGURE 8; FIGURE 10 is an example of a default form generated by the design tool for the semantic object "customer" in accordance with the invention; FIGURE 11 is an example of a default form generated by the design tool for the semantic object "order" in accordance with the invention; FIGURE 12 is an example of a default form generated by the design tool for the semantic object "shipping company" in accordance with the invention; FIGURE 13 illustrates an Add Component dialog box that provides an exemplary user interface for form and report customization; FIGURE 14 illustrates the form for the semantic object "order" in FIGURE 9, but with exemplary modifications to the form; FIGURE 15 illustrates the object view hierarchy that is associated with the form of FIGURE 14; FIGURE 16 is a flow diagram illustrating the steps performed in creating an action item template; FIGURE 17 is a flow diagram illustrating the steps performed in creating an action item component; FIGURE 18 is a flow diagram illustrating the steps performed to create an action group template; FIGURE 19 is a flow diagram illustrating the steps performed to create an action group component; FIGURE 20 is an exemplary routine for inserting an action item or action group component into a semantic object; FIGURES 21A-21B illustrate an exemplary routine for inserting an action item component into a group component; FIGURE 22 is an exemplary routine for inserting an action item template or action group template into an action group template; and FIGURE 23 illustrates an exemplary user interface for storing and retrieving data to and from a relational database using the custom application. Detailed Description of the Preferred Embodiment The invention is directed to a tool for creating and generating forms, reports, and queries in order to store and retrieve data from a relational database using an object model. By way of an overview, a user creates a graphic visual representation of the data to be stored in the database and the relationships that exist between various parts of the data. The visual representation, or "object model," is then transformed by the invention into a series of computer commands or function calls that cause a database program to create a corresponding relational database schema. The forms and reports interact with the relational database schema to facilitate the storage and retrieval of data in the database. For clarity in understanding the invention, a Table of Contents listing the major sections of the Detailed Description is set forth below: Table of Contents A Sample Object Model 13 Action Items and Action Groups 16 Semantic Object Modeling Definitions 17 Form and Report Generation 23 Object View Hierarchies 24 Exemplary Rules For Creating Default Forms 28 Form & Report Customization 35 Exemplary Routines for Building Form Definitions 37 Exemplary Routines for Building Report Definitions 41 C++ Classes 43 Action Items and Action Groups Revisited 45 Run Time View Creation 52 Canonical Run Time View Hierarchies 53 Form Run Time View Hierarchies 68 Run Time View Operations 75 An Overview of Semantic Object Modeling vis-a-vis Relational Database Tables 77 Referential Integrity and Database Transactions 80 Surrogate keys 80 Locking 80 Run Time View Operations 81 APPENDIX 96 With reference to FIGURE IA, a database design tool 50, hereinafter "design tool 50", creates a custom application 51 for storing and retrieving data to and from a database 52 in accordance with the invention. The database design tool operates in two discrete segments of time. The first is design time, which includes the following steps: (a) An object model 54 including semantic objects and defining relationships between two or more of the semantic objects is created by the user, using a template if desired; (b) The design tool generates a relational database schema 55 from the object model; (c) The design tool generates object view hierarchies 56 for each semantic object in the object model that will be used create forms and reports 57 for the semantic objects; (d) The user may customize the forms and reports 57 during design time to include more or less information or change their appearance, and may create forms and reports that have limited capabilities, e.g., read only, for security purposes, such as ensuring that a record is not changed by an unauthorized user; (e) The design tool creates "canonical" run-time views 58 that will be used to access the database 52 by combining information from the object model 54 and the relational database schema 55; (f) The design tool creates "form" run-time views 59 that will be used by the forms and reports to access the database 52 by combining information from the object view hierarchies 56 and the relational database schema 55; and (g) The canonical and form run-time views 58 and 59 are incorporated into the custom application 51, via run-time view operations 60. The second segment of time is run time, where the custom application 51 is used to access the database using run-time forms and reports 61. The run-time forms and reports 61 are adaptations of their design time counterparts, i.e., the relational database schema 55 information has been added via the form run-time views 59 to enable the forms and reports to communicate with the database 52 through run-time view operations 60. Thus, there is a one-to-one correspondence between the design time and run-time forms and reports. The run-time view operations 60 typically will generate a set of SQL statements to carry out a command. Exemplary commands executed by the run-time view operations include insert, update, query, and delete commands, and are described in detail below. It is noted that the underlying design time structure is no longer needed at run- time, because the custom application has embedded in it the information necessary from the object model and relational database schema to access the database. As indicated in FIGURE IB, the custom application is comprised of run-time forms and reports and run-time view operations only. With reference to FIGURE 1C, the design tool 50 runs on a computer 62 that has a processing unit 63 that is controlled by an operating system 64. The computer includes a memory 65, a keyboard 66, and a pointing device 67, e.g., a mouse, that are coupled to the processing unit for data input and computer control. A monitor 68 and printer 69 are also connected to the computer 62. The design tool 50 includes a built-in DBMS that is incorporated into the design tool 50, or in the alternative interacts with a commercially available DBMS, e.g., desktop database program (not shown), to communicate with the database 52. The memory 65 generally comprises, for example, random access memory (RAM), read only memory (ROM), as well as magnetic or optical storage media such as a hard drive, floppy disk, or magnetic tape. The computer 62 is typically a personal computer which may be, for example, a Macintosh™, International Business Machines (IBM™), or IBM-compatible personal computer. When used with IBM and IBM-compatible personal computers, the operating system 64 may be DOS based or may incorporate a windowing environment such as Microsoft Windows™ or OS/2™. The design tool may, however, run on other types of computers, such as a mainframe or mini-computer, and other operating systems. A Sample Object Model FIGURES 2A and 2B illustrate a graphical user interface display screen shot exemplary of that produced by the design tool 50 that allows a user to create and manipulate data that will be stored in the database. In order to more clearly explain the invention, a sample object model 70 is shown in FIGURE 2A. The object model 70 represents an extremely simple database that could be used by a company to track orders of a single product. To construct such a database, a user interacts with the graphical user interface to create the appropriate semantic objects. A semantic object simply represents a conceptual unit of data that the user desires to store in the database. The objects are called "semantic" objects because their definition and structure have meaning for the user developing the database. The object model 70 includes two semantic objects. A first semantic object 72 represents a customer that has ordered a product from the company. The semantic object customer has a number of components, including: company name, address, phone number, and fax number. The address, phone, and fax components are group components. Group components are designated with a triangle 73 to the right of the component name and can be expanded on the computer screen to show all the member components within the group. For example, the triangle by the address component has been expanded to show its member components, which include: street, city, state, and zip code. The phone and fax components each include an area code and a phone number. The customer semantic object 72 also includes a link to a second semantic object 74, which holds order information on an order-by-order basis. To accomplish this, the order semantic object 74 also includes a number of components. These are: order number, order date, a subtotal indicating the price of the product being ordered, the tax on that order, and a total price for the order. In addition, the order semantic object 74 includes a link back to the customer semantic object 72. FIGURES 3A and 3B illustrate default forms that have been created for the customer and order semantic objects 72 and 74, respectively. As is discussed above, a form allows data to be input into a database as well as to perform queries on data already existing in the database. With reference to FIGURE 3 A, a default customer form 80 includes a number of edit boxes for entering information regarding a particular customer. More particularly, an edit box 81 may be used to enter a particular company name, e.g., Wall Data. A series of edit boxes 82 may be used to enter the company's address, including street, city, state, and zip code; and the company's phone and fax numbers may be entered in the edit boxes 83 and 84. After all the information has been correctly entered, the user of the custom application may enter an appropriate command to store the record in the database. To perform a query for existing records, a user may enter query information into one or more fields in the form and then invoke an appropriate command. The records of the database will then be searched, and the results displayed on the screen. In addition to the company name, address and phone information, a user may also input information regarding orders for a particular company while using the customer form 80. A data entry grid 86 displays order information related to a customer. The data entry grid 86 includes a search button 88 that allows a user to search for orders that are unrelated to any customer, but which the user may want to associate with the customer identified in edit box 81. In general, each link that is associated with a semantic object for which a form is created will have a data entry grid and a search button. The function of the search button will depend upon how the object model is set up and the particular link associated with the search button. As will be discussed further below, the data entry grid 86 by default only includes access to the order number for a particular company's current orders. If desired, a user may customize the customer form 80 to allow additional order information to be presented, such as the date or dollar amount of each order. Forms generated by the design tool 50 will by default have an application's menu bar 89 that includes the following menu items: file, edit, record, view, forms, reports, window, and help. The application's menu stems from a semantic object that is automatically included in each object model. Using the "file" menu item in the menu bar, a user can close the current window, change the settings for print setup, or exit the program. The "edit" menu item includes the ability to cut, copy, paste, and delete text, as well as resetting a field within the form. The "record" menu item allows a user to save a record, set search criteria, find a record, go to the first, previous, next, and last records, delete a record, and reset a form. Using the "view" menu item, a user can toggle between displaying and hiding the status bar and toolbar of a form. The "forms" menu item allows a user to retrieve any of the forms that were constructed for a semantic object in an object model. The "reports" menu item is a quick way to issue printing commands for a report in the object model. The "window" and "help" menu items allow arrangement of icons and searching for help on topics regarding the design tool, respectively. In addition to the application's menu bar 89, each form also includes a toolbar 91 that includes popular commands that are identified by icons in the toolbar. They include, from left to right, cut, copy, paste, save, query, clear form, open a related form, open first record, open the previous record, open the next record, open the last record, and display help contents. FIGURE 3B illustrates a default order form 90. The order form 90 includes edit boxes 92 and 94 that allow an order number and order date to be input into the database. Edit boxes 96, 98, and 100 provide areas for entering a subtotal, tax, and total, respectively, associated with a current order. It should be noted that the object model, and hence form, will often be set up so that data in some of the fields are automatically generated in response to data entered in other fields. For example, once a subtotal is entered, the tax and total may be automatically computed. A platform 102 includes an edit box 104 and a search button 106. Using the search button 106, a user can query the database for customers matching a name entered in the edit box 104. For example, if a "W" has been entered in the edit box, all customers starting with that letter will be displayed. The edit box 104 may also be used to create a customer to be associated with an order. The use of queries is discussed in greater detail below. As with the customer form 80, the order form 90 may be customized to provide more or less information regarding either orders or customers, as desired. See FIGURES 13-15 and accompanying text. FIGURES 4A and 4B illustrate default reports that have been created for the customer and order semantic objects 72 and 74, respectively. The customer report in FIGURE 4A includes two exemplary records. A first record 110 refers to a customer whose company name is Starbucks Coffee and a second record 112 refers to a customer whose company name is Wall Data. Each record 110 and 112 includes the address, phone number, and fax number for the customer. In addition, the customer record includes the order numbers that have been placed by that customer. In the record 110 an order number column 214 indicates that order numbers 3 and 4 have been placed by Starbuck's Coffee. Likewise, an order/order number column 116 in the record 112 shows that order numbers 1 and 2 are associated with the customer Wall Data. With reference to FIGURE 4B, a default report for the semantic object order includes four exemplary orders listed sequentially that are contained in the database. Specifically, column 118 lists the order number; column 120 the date of each order; column 122 lists the customer (company name) associated with each order; and columns 124, 126, and 128 list the subtotal, tax, and total for each order. Action Items and Action Groups Action items (actions) and action group components may be placed into a semantic object to determine a user's access to a form that is created for a semantic object. Exemplary action item components include: arrange icons, copy, cut, paste, delete field, delete record, find, open form, print report, and run script. Action group components contain other actions that a user can perform or choose from within a semantic object. For example, the separate actions new, open, close, and exit make up the file action group component. Similarly, the actions undo/redo, copy, cut, and paste together form the edit action group component. Other exemplary action group components include: forms, help, record, reports, view, and window. Action items directly contained within a semantic object become command buttons on a form associated with the semantic object; action group components are represented by items on a menu bar. Actions within an action group are displayed as menu items within popup menus on the menu bar resulting from that action group. An action group inside of an action group shows up as a cascading menu. When an action group is added to a semantic object, the default applications menu bar is replaced by the menu bar that is created from action group component(s) in the semantic object. Thus, action groups may be used to limit access to commands in a form. An example will clarify this description. FIGURES5A-5B illustrate the object model 70 of FIGURE 2A, but where three exemplary action groups file 131, record 132, and help 133 have been added to the customer semantic object 72. An action item "related form" 134 has also been added. In FIGURE 5A, the actions that make up the action group components file 131 and help 133 are displayed. The individual actions for the action group file 131 include: close window 135a, menu separator 135b, print setup 135c and exit 135d. The individual actions for the action group help 133 include: help contents 136a, search for help 136b, help on help 136c, and about 136d. FIGURE 5B illustrates the actions that comprise the action group record 132. These actions include: save 137a, save as new 137b, query mode 137c, find 137d, first 137e, previous 137f, next 137g, last 137h, reset form 137i, clear form 137j, and delete record 137k. FIGURE 5C illustrates a default form 139 that has been created for the (revised) semantic object customer 72. As can be seen, the applications menu bar 89 in FIGURE 3 A has been replaced with a custom menu bar 140. The custom menu bar includes three menu items 141, 142, and 143 that correspond to the action groups components 131, 132, and 133, respectively. Selecting a menu item will display menu picks for each of the actions in the action group associated with the selected menu item. For example, in FIGURE 5D the record menu item 142 has been selected, displaying the actions that were set forth in FIGURE 5B, along with keyboard commands that will invoke those actions. With reference again to FIGURE 5C, underneath the custom menu bar 139 is a windows button 146 entitled "Show Related Form" that was created as a result of the action item 134. Depressing the windows button 134 will display the form of a semantic object that is related to the customer form, e.g., if orders was highlighted, the orders form would appear. For a further discussion of actions and action groups and their implementation, please see FIGURES 16-22 and the accompanying text. Semantic Object Modeling Definitions Now that the reader has a rudimentary knowledge of semantic object modeling, forms, and reports, the invention will be described in greater detail. Prior to doing so, a compendium of terms that are particular to semantic object modeling and the invention are defined below. With the exception of the term semantic object, definitions that refer to terms that are otherwise defined in the list are presented in italics. action group A model component that results in a menu being placed on a form for allowing access to commands. action item or action A model component that results in a button being placed on a form or an item in a menu for performing a task specified by the action. cardinality The maximum or minimum number of instances allowed for a model component. Single-value components have a maximum cardinality of one; multi-value components have a maximum cardinality greater than one. control A portion of a graphical user interface in a form or a report that is used to input or display information, e.g., a list box, edit box, grid, or check box in a form. data component A simple value component, group component or object link. group A logical grouping of data components that are commonly found together; for example, an address may be defined as a group that includes a street name, city, state, and zip code. identifier A model component that is used to choose between object instances, may be unique or nonunique. In the design tool user interface, model components that are identifiers are designated with two asterisks if they are unique and one if nonunique. model component or A type component or a data component. component These are called "attributes" in the '997 application. object link A model component that defines a relationship between a pair of semantic objects; object links come in pairs, one in each of the semantic objects being related. object model A collection of semantic objects that represent data to be stored in a database. Referred to as an "album" in the '997 application. object view hierarchy A hierarchy of view objects beginning with a root view object. parent link An object link used to define a classification hierarchy among semantic objects (paired with subtype links); for example, a lawyer semantic object might have a subtype link to an associate semantic object. path cardinality An indication of the number of instances allowed for a component, its parent, its parent's parent, etc., starting from the component and traversing back to the semantic object which ultimately contains the component. A test based on path cardinality typically looks to see if any component in the chain has a maximum cardinality greater than one. recursive link An object link where the referenced semantic object refers back to the semantic object that contains the link. referenced semantic The semantic object that contains an object object link's pair. root view object A view object based on a semantic object. run-time hierarchy A hierarchy of run-time view elements beginning with a root view object. semantic object A representation of an item about which data is stored in a relational database. semantic object A hierarchy of model components that hierarchy comprise a semantic object. Top-level components are defined as being "directly contained" by the object; second-level components are considered to be "members" of a top-level component; third-level components are "members" of a second-level component; and so on. simple value component A model component that represents a single piece of data, such as a name, salary, social security number, that is stored for an item represented by a semantic object. subtype group A group that may include subtype links and other subtype groups; are used to enforce counting constraints across subtype links. subtype link An object link used to define a classification hierarchy among semantic objects (paired with parent links); for example, an associate semantic object might have & parent link to a lawyer semantic object. template An interface that is used to create and store the attributes of a corresponding component. Referred to as a "profile" in the '997 application. type component A subtype group, subtype link or parent link. view element Represents either a single column or a collection of columns in a database and is based on a model object. view object A view object is based on either a semantic object or a model component in the object model and is used to store information for forms and reports. Each component in an object model has a template from which it is created. However, a component is associated with a particular semantic object, and its properties can be overridden from those defined in the corresponding template. Templates are used to allow a user to easily change all the components in the semantic object data model by changing the template from which the components are derived, as many components of the same type might be placed in different semantic objects. With reference again to FIGURE 2 A, the invention includes a catalog 150 that includes a template manager window 152 from which a user may select a predefined template; alternatively, the user can create his/her own templates which are then stored in the template manager. The template manager is used when defining components for a semantic object, and includes a listing of the semantic objects in an object model, as well as data items, data groups, action items, and action groups that may be added to the semantic objects in the object model. These are listed in a "show only" window 154. Using the template manager, a user can drag and drop a predefined or newly created template into a semantic object in order to create a corresponding component within that semantic object. The components within a semantic object have icons and other means that indicate to the user of the design tool the properties of each component. As referenced in the window 154, semantic objects are indicated by an icon 156 (page), data items are indicated by an icon 158 (box), data groups by an icon 160 (group of boxes), action items by an icon 162 (lightning bolt), and action groups by an icon 164 (multiple lightning bolts). Object link components are shown outlined, as shown by reference numeral 166 in the semantic objects 72 and 74. In addition to the properties described above, each component within a semantic object indicates whether a user has defined the component to refer to a particular instance of the semantic object. Components that refer to a particular instance of the semantic object are called identifiers. Identifier components may be unique or nonunique. A unique identifier defines a unique instance of the semantic object. For example, in FIGURE 2A the component company name in the customer semantic object 72 has a pair of asterisks 168 which indicate that the customer's company name uniquely identifies a particular company. If the indication is shown as a single asterisk only, the component refers to a particular instance of the semantic object but the component may not be unique. Finally, the lack of any asterisks to the left of a component indicates the component is not used to specify a particular instance of a semantic object. In the lower right-hand corner of each component is an indication of the component's cardinality. This is shown as a subscript consisting of a pair of integers having the form "n-m." The "n" refers to the minimum cardinality of a component. This is the minimum number of instances of the component that the semantic object must have to be valid. For example, the customer semantic object 72 has a group component "address" having a cardinality 0-1. The first numeral "0" indicates that a company need not have an address. The second numeral refers to the maximum cardinality, i.e., the maximum number of instances of the component that a semantic object can have. The maximum cardinality of the group component address is "1," thereby dictating that a company may at most have a single address. If this value were "N," multiple addresses would be allowed. A user may create semantic objects by selecting a "create semantic object" option from a tools menu in the graphical user interface and entering "customer" and "order." Once the semantic objects have been created, a user then enters components into those semantic objects by choosing a template of the desired component and dragging the template into the boundary of the semantic object. For example, to create the company name component, the user selects the company name template from the template manager 150 and drops it into the customer semantic object 72. A property sheet 170, shown in FIGURE 2B, may be used to change any of the properties of a component, including the component's name, data type, minimum and maximum cardinalities, etc. The particular property sheet shown in FIGURE 2B is for the "company name" component. Using the user interface shown in FIGURES 2A and 2B, a user can create relationships between the semantic objects by selecting a semantic object and then dragging the object into the bounds of another semantic object. For example, to create the relationship between the customer and order semantic objects, a user can select the customer semantic object and place it within the physical boundaries of the order semantic object. This action causes the design tool to create an object link component called "order" and place it in the customer semantic object, as well as to create an object link component called "customer" and place it in the corresponding order semantic object. Form and Report Generation FIGURE 6A is a flow diagram that illustrates exemplary steps taken by the design tool 50 to create the custom application 51 in accordance with the invention. At block 200, a user is prompted to enter an object model that reflects the data for which a custom application is to be generated. This is accomplished by having the user create semantic objects, and defining that object's model components and links to other semantic objects. In one embodiment of the invention the design tool 50 provides templates that give users a "start" for creating their object model. For example, templates may be available for keeping track of an inventory for a small business, creating a roster for an intramural team, keeping track of the attorneys and associates in a law firm, etc. The current object model, whether it be from a scratch design, a template, or a modified template, is then displayed at block 202. At block 204, a test is made to determine whether any modifications to the current model have been made. If modifications have been made, the object model is changed accordingly at block 206, and the program loops to block 202 where the current object model is again displayed. If the user is satisfied with the object model, i.e., additional modifications are not desired, a test is made at block 208 to see if the user wishes to preview any forms or reports that will be generated for each semantic object in the object model at run-time. If the user wishes to preview a form or report, a view routine is called at block 210. An appropriate routine for performing this task is set forth in FIGURE 6B. Otherwise, a test is made at block 212 to determine whether a database application is to be created from the current object model. If the user wishes to further modify the current object model, or any of the forms and reports that will be created therefrom, the program loops to block 202. When the user is content with the current object model, as well as with the forms and reports that will be generated from the object model, the program proceeds to block 214, where the database schema is generated from the object model. At block 216, the custom application 51 is generated based on the object model. At block 218, the custom application 51 is run. The custom application 51 is now in run time, and the user is free to store and retrieve information from the database. With reference to FIGURE 6B, an exemplary routine for generating default forms and reports in accordance with the invention is illustrated. At block 230, a root view object for which a default form or report is to be generated is selected. At block 232, an object view hierarchy for the selected root view object is created. Once the object view hierarchy is created, a default form and report is constructed for the root view object using the object view, as indicated at block 234. Exemplary rules for creating default forms from the object view hierarchy are set forth in Tables 1-3 below. An exemplary routine that ties all of the form generation rules together is illustrated in the Appendix as LISTING L2. An exemplary routine for building default reports is illustrated as LISTING L6. Once created, the default forms and reports are displayed, as indicated at block 236. The routine then returns to block 202 of FIGURE 6A. Object View Hierarchies An object view hierarchy is a data structure that is used when generating forms and reports. The structure of an object view hierarchy is related to the structure of semantic objects, but is separate therefrom because a form or report typically contains information about more than one semantic object. In addition, there may be many forms or reports based on a single semantic object. Each form and each report will have a separate object view hierarchy. To be more specific, an object view hierarchy is a hierarchy of "view objects," where each view object is founded from either a semantic object or a model component in the object model. An object view hierarchy stems from a root view object, defined as a view object for which a form or report is to be generated. A root view object always stems from a semantic object in the object model (as opposed to a model component). As is described in detail below, view objects are containers that hold information necessary for form and report generation. For example, a view object corresponding to a link will include information about the semantic object coupled to the link. The type of information held in any particular view object is determined by the object type, e.g., simple value. What is contained in an object view hierarchy is dictated by default rules that are set forth and discussed below. FIGURE 7 illustrates the class hierarchy for a generic view object 240. From the view object 240 stems a root view object 242 and one or more view components 244. There are eight different categories of view components in an object view hierarchy. The categories are based on categories of model components available in the object model. The '997 application described seven of these: simple value, formula, data group, and object link, which are has-a type components; and parent link, subtype link, and subtype group, which are is-a type components. Formula attributes (components), which were described in the '997 application, have been combined with simple value components in the current implementation of the design tool. Specifically, simple value components have a source property that may be set to "script" and a formula entered into the formula property. The two categories not described in the '997 application are action item and action group components. These allow menus and buttons to be added to forms and are described in detail below. From the following stem the view component categories: simple value 246, data group 248, object link 250, parent link 252, subtype link 254, subtype group 256, action 258, and action group 260. The object view hierarchy generation rules will take these categories into account. The following rules govern what can be included in an object view hierarchy. Exemplary default rules, defined in a moment, will further limit reach of an object view hierarchy. FIGURE 8 illustrates an object model 262 that will be used throughout the remainder of this discussion. The object model 262 is a more complicated version of the object model 70 in FIGURE 2A. The object model includes the following semantic objects: customer 264, order 266, item 268, shipping company 270, and supplier 272. For the examples provided after each rule, it is assumed that a view object based on the semantic object order 266 in FIGURE 8 is the root view object. Root View Objects: Root view objects can only include view components based on model components directly contained by (topmost level) the semantic object upon which the root view object is based. For example, the root view object order can contain: order number, order date, customer, line item, subtotal, tax, and total. For a listing of the data held by root view objects, see the root view object class described in FIGURE 25A and accompanying text. Simple Value View Components: View components based on simple value model components cannot contain any other view components. Order date, subtotal, tax, total, unit cost, quantity, and extended price are examples of simple value view components that cannot contain any other view components. For a listing of the data held by simple value view components, see the simple value view component class described in TABLE T19, which can be found in the Appendix. Group View Components: Group view components can only contain view components based on model components that are directly contained by the group view component's base model component. Consider the group view component line item; it can only contain item, unit cost, quantity, and extended price. For a listing of the data held by group view components, see the group view and subtype group view component classes described in Tables T16 and T20, respectively, and accompanying text. Object Link View Components: Object link view components based on model components that are directly contained in the referenced semantic object of the model component upon which the object link view component is based can be included. Consider the object link view component "customer"; it can contain company name, address, phone, fax, and customer contacts. However, it is noted that view objects based on model components of semantic objects that are referenced by a recursive link are not included. For a listing of the data held by object link view components, see the object link view, subtype view, parent view component classes described in Tables T15, T17 and T18, respectively, and accompanying text. FIGURE 9A illustrates a semantic object hierarchy 280 for order 266. With reference to both FIGURES 8 and 9 A, the semantic object order directly contains seven model components: an identifier component order number 282; a simple value component order date 284; a link component customer 286; a group component line item 288; and simple value components subtotal 280, tax 292, and total 294. The group component line item 288 directly contains a link component item 295; and simple value components unit cost 296, quantity 297, and extended price 298. That is the extent of the semantic object hierarchy for order 266. FIGURE 9B illustrates an object view hierarchy 302 for the semantic object order 266, and includes a partial listing of all of the view objects based on model components that can be included in accordance with the rules set forth above. A root view object order 304 is based on the semantic object order 266. The top-level view objects include: order number 306, order date 308, customer 310, line item 312, subtotal 314, tax 316 and total 318. The second level components include the following—under customer: company name 320, address 322, phone 324, fax 326, customer contacts 328, and order 330; and under line item: item 332, unit cost 334, quantity 336, and extended price 338. The third-level components include: (a) components associated with the groups directly contained by customer 310, i.e., the components that are directly contained by the group components address 322, phone 324, fax 326, and customer contacts 328, which are not shown for brevity, and (b) the components directly contained by item 332, which is a link view object. The components directly contained by item 332 include: product name 340, product type 342, product number 344, standard cost 346, location/bin 348, sales price 350, comments 352, order 354, supplier 356, and shipments 358. For brevity, only a sampling of the fourth-level components are shown. These include: company name 360 and supplier contacts 362 under supplier 356; and date shipped 364 and date received 366 under shipment 358. It should be appreciated from the foregoing, however, that the object view hierarchy may include any component that is referenced by a semantic object, whether it be directly contained in the semantic object, in a group, in a link, or through multiple (nonrecursive) links. While an object view hierarchy can contain an enormous amount of information, the design tool has default rules which govern what will initially be in an object view hierarchy. That is, the rules attempt to anticipate what information will be important to a user that requires a form or report concerning a semantic object. As is discussed in greater detail below, the design tool enables a user to change what is included in a form or report, which in turn will modify the object view hierarchy from its default structure. The default rules, presented directly below, distinguish between link and nonlink components, and also take into account whether or not a link is recursive. (1) NonLink Components: All nonlink model components of the base semantic object, at all levels, are included in the object view. Thus, this excludes model components that are contained in semantic objects that are referenced by links. (2) NonRecursive Links: For nonrecursive links, review the top- level model components of the semantic object referenced by the link and include any model components carrying a "unique" or "non-unique" identifier. If none of the top-level model components have such a designation, include the first top-level model component encountered. All other model components are not included. (3) Recursive Links: If an object link is recursive, do not include it in the object view. In an alternative embodiment, each of the single-value groups under a nonrecursive link are evaluated and those which have a "unique" or "nonunique" component are also included in the group. This rule is applied recursively. FIGURE 9C illustrates the object view hierarchy 302 of FIGURE 9B, but truncated to include only that information that is provided under the default rules (l)-(3). The top level components order number 306, order date 308, line item 312, subtotal 314, tax 316, and total 318 remain because they are nonlink components, as dictated by rule (l). Customer 310 remains because it is a nonrecursive link. With regard to the second level, company name 320 is the only model component stemming from the link to a customer that is included in the default; it is a top-level model component of the semantic object referenced by the link (customer) and carries a "unique" identifier, as dictated by rule (2). No other model components are considered in accordance with the rule, and thus that branch is finished. The only other branch to consider is line item, as the other branches were all data components. Line item has a nonrecursive link to item 332, so item 332 remains. Line item also has member components unit cost 334, quantity 336 and price extended 338, which are included in accordance with rule (1). At the fourth level, the model components of item 332 must be considered. Item 332 has two "identifier" components in its topmost level: product name 340 and product number 344, which are included under rule (2). Since each branch has been considered, the object view hierarchy 302 is complete. Now that an understanding of object view hierarchies has been achieved, the default rules for form and report generation are discussed. Exemplary Rules For Creating Default Forms Default forms are created for each semantic object in the object model at run¬ time, or earlier if the user requests them, e.g., using the routine of FIGURE 6. The rules set forth in Tables 1-3 establish the interface or "controls" that are generated for the model components associated with a semantic object in creating a default form. A control is the interface found within a form (or report) that dictates the format of the information in the form, such as a box or grid. It is noted that, while a single semantic object may have several forms (or reports), each begins with a default structure that may be subsequently modified. It is this default structure that is referred to throughout this description. Three factors are used in determining the controls that are created for a default form: (1) The cardinality of the model component (which may be a link); (2) The path cardinality of the parent of the model component; and (3) The data type of simple value components. The cardinality of a model component is the number of instances of data that may be stored in a database for a corresponding model component. The path cardinality of a model component is considered to be either one or greater than one for form generation purposes, and is determined by reviewing the cardinalities of a component through any containers (i.e., group components) to the semantic object in which the component is located—in other words, the cardinality of itself, its parent (if one exists), its parent's parent (if one exists), and so on, until the top-level of the root view object has been reached. A simple value component's data type will dictate what type of mark goes into its associated edit box, if any. A model component will have a cardinality greater than one if more than a single instance of the component may exist. The path cardinality of a model component will be greater than one if any component in the chain, from that model component to the semantic object upon which the form is based, has a cardinality greater than one. The path cardinality of the parent of a model component will be greater than one if any component in the chain from the parent of the model component to the semantic object has a cardinality greater than one. Default rules for control generation are set forth in TABLES 1-3 below. TABLE 1 refers to controls associated with group model components; TABLE 2 refers to controls associated with link model components; and TABLE 3 depicts the controls for the data components. The interaction between and explanation of the control generation rules will become more apparent when referenced in conjunction with default forms that have been created for some of the semantic objects in the sample object model 262 illustrated in FIGURE 8. While the object view hierarchies for each semantic object are not presented specifically, FIGURES 10, 11, and 12, respectively, illustrate exemplary default forms for the semantic objects customer 264, order 266, and shipping company 270. Each event in TABLES 1 and 2 is considered. The following format is used to refer to the lineage of a model component: semantic object_child_ j grandchild_ j great grandchild, etc. The generation of controls for group components will be addressed first. TABLE 1 : Controls Generated for Grou s The first entry in TABLE 1 is groups that have a maximum cardinality of one and whose parents have a path cardinality of one. Such groups are represented by a "group box," which is a term used to describe a border that encompasses a control related to each member in the group. Examples of groups that have a maximum cardinality of one and a "parent" path cardinality of one are shown in a default form 400 for the semantic object customer, illustrated in FIGURE 10. They include customer address, customer_phone, and customer fax and are represented by group boxes 402, 404, and 406, respectively. Inside each group box are controls for the member components for that group. For example, the group box 402 includes controls 408 for the street, city, state, and zip code member components. The specifics of control generation for these and other data components are discussed below in TABLE 3 and accompanying text. The second entry in TABLE 1 is groups that have a maximum cardinality greater than one and whose parents have a path cardinality of one. Such groups are represented by a grid. In the embodiment of the invention shown, a grid includes a representation of each member component in the group, e.g., the name of the member component on a title row; and has additional rows underneath the title row for data entry. An example of this type of group is customer_customer contacts, where a grid 410 has been created. The grid 410 includes a title row 412 that includes an identifying label "Customer Contacts"; a subtitle row 414 that has identifying labels representing the group's member components; and data entry rows 416. The third entry in TABLE 1 is groups that have a maximum cardinality of one and whose parents have a path cardinality greater than one. Such groups are not directly represented with a title for a control. Rather, the member components in the group appear as columns in a grid that was constructed for a parent component. An example of this type of group is customer customer contacts direct line. With reference to the grid 410, the member component direct line includes an area code, phone number, and extension. Each of these have been identified in the subtitle row 414. However, the title "Direct Line" by default does not appear in conformance with the rules in TABLE 1. As will be discussed below, a user can customize the form to include the "Direct Line" label above the area code, phone number, and extension components. Finally, the fourth entry in TABLE 1 is a group that has a maximum cardinality greater than one and whose parents have a path cardinality greater than one. Such groups are represented by a detail grid that appears in the proximity of a master grid, where the master grid was created for a parent somewhere in the path from the model component group to the semantic object. An example of a group that has a maximum cardinality greater than one and a parent path cardinality greater than one is customer customer contacts important dates and is represented in FIGURE 10 by a detail grid 420. The detail grid 420 includes a title row 422 identifying the group name of "Important Dates"; a subtitle row 424 listing each member in the group (Event and Event Date); and data entry rows 426 underneath the subtitle row. The detail grid 420 is part of a "master-slave" scheme in that the contents in the detail grid will change as different customer contacts in the grid 410 are entered or existing customer contacts highlighted. The rules governing the creation of controls for links will now be addressed. With reference to TABLE 2, the first event is links that have a maximum cardinality of one and whose parents have a path cardinality of one. Such links are represented by a "platform" and a search button. A platform is similar to a group box, and is a term used to describe a border that encompasses a control for each component of the referenced semantic object or member component that is of interest in the form, and thus included in the platform. The platform also includes a search button, which is a standard Windows push button that is used at run-time by the user to perform a query. If the user has typed any information into any of the fields contained within a platform, the information is taken into account when the query is performed. With reference to FIGURE 11, an example of a link that has a maximum cardinality of one and a parent path cardinality of one is order customer and is shown in a default form 430 for the semantic object order. The link is represented by a platform 432, a label 434 of "Customer," and a search button 436. Also included in the platform 432 is a control 438 for company name, which is an identifying model component of the semantic object customer. See the default object view hierarchy in FIGURE 9C. Other model components for this object may also be added to the form, but are not included by default. The second entry in TABLE 2 refers to links that have a maximum cardinality greater than one and whose parents have a path cardinality of one. These links are represented by a grid, in the same manner as groups having the same coordinating characteristics. An example of this type of link is customer order in the customer form 400 of FIGURE 10. In accordance with the rules, a grid 440 has been created identifying the orders for a customer. The grid 440 includes a title row 442 that includes an identifying label "Orders"; a subtitle row 444 that has an identifying label for the order number; and a data entry row 446. Again, other components from the link to the semantic object orders may also be added to the form, but are not included by default. If additional member components are added, they would be represented by additional columns in the grid 440. The third entry in TABLE 2 is links that have a maximum cardinality of one and a parent path cardinality greater than one. As was discussed above in regard to groups (the third entry in TABLE 1), these links are not directly represented in a control. Rather, one or more member components from the semantic object referenced by the link appear as columns in a grid that was constructed for a parent component. An example of this type of link is order line item item, as shown at grid 450 in the object form 430 in FIGURE 11. The grid 450 includes columns 452 for entering information about an item's product name and product number, but a label of "Item" itself is not included in accordance with the rules. Again, a user may wish to customize the form to include a label for "Item" that would appear above the product name and product number, if desired. The last entry in TABLE 2 refers to links that have a maximum cardinality greater than one and a parent path cardinality greater than one. Such links are represented by a detail grid that appears in the proximity of a master grid, and includes a search button. An example of a link that has a maximum cardinality greater than one and a parent path cardinality greater than one is shown in a default shipping company form 470 illustrated in FIGURE 12. A detail grid 472 includes a title row 474 identifying the referenced semantic object "Item" upon which the grid is based. A subtitle row 476 lists the member objects that are included by default in the detail grid 472. These include both the product name and the product number. The detail grid 472 is part of a "master-slave" scheme and is based on the shipment of interest (shown in a master grid 478). Thus, the contents of the detail grid will change depending upon the particular shipment being entered or reviewed in the master grid 478. TABLE 3 refers to controls generated for data components. Controls for data components typically include a title (listing the name of the component), a data entry location, and may also include a "mask." A mask is a preset set of symbols that facilitate entry of data into the appropriate places. The data type will determine the type of mask, if any, a model component will receive. For example, a currency mask will insert a "$ ." in the data entry location. A date mask will insert: " - - " or " / / " in the data entry location. TABLE 3 : Controls Generated For Data Items FIGURES 10-12 illustrate some of the controls described in TABLE 3. In FIGURE 11, for example, data entry location 480 at the upper left of the order form 430 depicts an example of a numeric mask for the data component order_order number. An example of a date mask is illustrated in data entry location 482, for the data component order order date. The data entry location 438 for order customer company name is an example of an "edit + label" control for a text data component. Examples of currency masks are illustrated in data entry locations 484, corresponding to the data components order subtotal, order tax, and order total. Examples of the other data components are either not pointed out specifically or not shown in the example forms in FIGURES 10-12, but the controls generated using the rules above will be apparent from the controls that are shown and discussed. Form & Report Customization An important aspect of the invention is the ability to customize forms and reports before run-time so that the form or report includes access to information in the database that is important to the user. In addition to customizing the information contained in a form or report, the look and feel of the form or report may also be modified using the design tool. The underlying processes for implementing aesthetic modifications are not discussed herein, as they will be apparent to those skilled in the art. The design tool includes a number of user interfaces through which a form or report may be modified. For example, to remove reference to a model component while viewing a form or report, a user can simply highlight and then delete the information using the pointing device and/or keyboard. In doing so, the model component will be deleted from the object view hierarchy for that form or report, and the form or report itself will be automatically updated. A control palette may be used to add unbound controls, i.e., a control that is not bound to a model component, to a form or report. Another user interface that may be used both to add and remove information about model components from forms or reports is an "Add Component" dialog box 490, illustrated in FIGURE 13. The dialog box 490 is separated into left and right halves 492 and 494. The left half 492 displays the semantic object upon which the form is based, in this instance its "order," as well as semantic objects and model components that are linked to the semantic object upon which the form is based. The right half 494 displays the contents of a container corresponding to a semantic object or a model component that has been highlighted in the left half 492. In the illustration, the model components directly contained by the semantic object order are shown in the right half 494. In addition, the group line item has been expanded to show the model components that it directly contains. Model components that are included in an object view hierarchy for a form or report have checkmarks 496 beside their names. Model components may be added or removed from a form or report by selecting or deselecting the model component of interest in the right half 494. The object view hierarchy, and hence form or report, is automatically updated to incorporate the selection. FIGURE 14 illustrates the form 430 for the semantic object "order" in FIGURE 11, but including exemplary modifications made by a user in customizing the form. Specifically, the model component "product number" has been removed from the grid 450. This is accomplished, for example, by selecting and then deleting the product number column in FIGURE 11 or by invoking the Add Component dialog box shown in FIGURE 13 and double-clicking on "product number." In any event, by issuing such a delete command, the object view hierarchy for the form 430 is automatically updated by the design tool, and the product number model component is removed from the form. Model components may be added in much the same way. The model components order_customer_phone and order customer fax have both been added to the form 430. The results of these additions are shown in the platform 432, where inner platforms 498 and 500 have been created for the phone and fax group components, respectively. Each platform is labeled after its respective group component. Within the platform 498 are edit boxes 502 and 504 for the area code and phone number, respectively, corresponding to the phone number of a customer. Within the platform 500 are edit boxes 506 and 508 for the area code and phone number, respectively, corresponding to a customer's fax number. The foregoing is intended to give just a sampling of what may be accomplished in the way of form customization, and those skilled in the art will appreciate the great extent to which any form or report may be changed to accommodate a user's needs and preferences. FIGURE 15 illustrates the object view hierarchy 302 from FIGURE 9C, but modified in response to the changes made to the form in FIGURE 14. As can be seen, the model component order line item_item_product number has been removed, and model components order_customer_phone 510 and order customer fax 512 have been added. These reflected changes illustrate how the design tool utilizes object view hierarchies to store the information needed for generating forms and reports for semantic objects. Exemplary Routines for Building Form Definitions Exemplary routines for building a form definition, i.e., a hierarchy of form containers, in accordance with the invention are set forth in the Appendix as pseudocode LISTINGS L1-L4. The routines encompass the form generation rules described in Tables 1-3. Those skilled in the art will appreciate how to generate the code necessary to display or print the form definitions. The routines are written in pseudocode that resembles the programming language C++. An overview of selected lines in the routine is provided for clarity, particularly for those not versed in C++. LISTING LI illustrates skeletal class descriptions showing the essential features of the C++ classes used in the routine of LISTING L2. With reference to LISTING LI, the classes created include: FormObject at lines 10-170; Form at lines 180-230; Menultem at lines 240-290; PopupMenu at lines 300-350; Grid at lines 360-410; Platform at lines 427-470; and GroupBox at lines 480-530. The class FormObject is a base class for the Form, PopupMenu, Grid, Platform and GroupBox classes. The class Form is created for a root view object; the class Menultem is created for actions inside an action group; the class PopupMenu is created for action group view objects; and the class Grid is created for multi-valued view components of all types. The class Platform is created for single-valued, object link components. The class GroupBox is created for single-valued, group view components. The classes created on the second page of LISTING LI include GridColumn at lines 540-600, CheckBoxColumn at lines 610-660, EditGridColumn at lines 670-720, Formltem at lines 730-790, ActionButton at lines 800-850, SearchButton at lines 860-910, CheckBoxItem at lines 920-970, and Editltem at lines 980-1030. The class GridColumn is a base class for the classes CheckBoxColumn and EditGridColumn. The class CheckBoxColumn is created for Boolean simple valued columns in a grid. The class EditGridColumn is created for all other simple valued data items in a grid. The class Formltem is a base class for the classes ActionButton, SearchButton, CheckBoxItem, and Editltem. The class ActionButton is a class created for action items that are not an action group; SearchButton is created for object links that have a path cardinality of one; CheckBoxItem is created for Boolean simple valued object view components with a path cardinality of one; and Editltem is created for all other simple valued object view components with a path cardinality of one. Single-valued group or object link view components that have a path cardinality greater than one do not generate specific form objects, and thus a separate class is not required to hold information related to them. It is noted that while the pseudocode does not show the data or implementation of the operations specified, these will be apparent to those skilled in the art. With reference to LISTING L2, line 20 declares a parameter called pViewObj that points to a "current" view object in an object view hierarchy. When the routine is called for the first time, pViewObj will point to a root view object that is based on a semantic object for which a form is being created. Subsequent (recursive) calls will address lower level view objects. Line 30 declares a parameter called pFormObject that points to a form object that will hold the form definitions for the current view object. The types of form objects that pFormObject may point to include: a form (created for root view objects), a grid (created for multi-valued view objects), a platform (created for single-valued links), or a group box (created for single-valued groups), as described above. At line 70, the label of the current form object is set to the title of the current view object. The title will be the name of view object, unless a caption has been created by the user. Lines 80-100 define local variables "iter," pChild, and pNewFormObject that the routine will use. The variable iter will be used to iterate across the contents of the current view object. During a loop bounded by lines 110-770, iter will return each child of the current view object, in turn. The block bounded by lines 110-330 takes into account action item and action group view objects. At line 130, a test is made to determine if the current child view object is an action item or action group component. If the current child is an action item or action group, a test is made at line 150 to determine if the current child is an action group. If the current child is an action group, at line 170 a local variable pNewMenu is declared. At line 180, a new popup menu is created and placed in pNewMenu. This routine is then called recursively at line 190, thereby adding menu items to the new menu. At line 200, the menu is added to the current FormObject. If the child was not an action group, the block designated by lines 230-320 is executed. At line 240, a test is made to determine if the current FormObject is an action. If the current FormObject is an action, at line 260 a menu item is created and inserted into the form object. Otherwise, at line 300, an action button is created and inserted into the current FormObject. This completes the block designated by lines 130-320. At line 340, is a test is made to determine if the child of the current view object that is under consideration is multi-valued, i.e., if it has a maximum cardinality that is greater than one. In accordance with the rules, multi-valued model components will be displayed in a grid. If the child is multi-valued, a grid is created at block 390. Line 400 is a recursive call to define the contents of the grid. The type of grid created will depend upon whether a grid was also created for the current view object or any parents in the line of succession to the root view object. If so, the child's grid will be a detail grid dependent upon the (master) grid that was created for the parent (or a successor thereto). Otherwise, the newly created grid is not a detail grid. At line 410, the grid is inserted into pFormObject. Lines 430-760 are directed toward children that are based on single-valued components only. At line 430, a test to made to determine if the container that was created for the current view object is a grid. If the current form object is a grid, a test is made at line 460 to determine if the child of the current view object is a link or a group. As dictated by the rules, in this case only the contents of the link or group view component are added to the current form object. This is accomplished by the recursive call at line 480. At this point, the else determination at line 500 refers to a child that must be a single-valued, simple value view object. At line 530, a grid column is created and added to the current form object. A suitable routine for creating grid columns based on the data type of the simple value view component is set forth in LISTING L3. To reach the else determination at line 560, the child view object must be single valued and the current view object must not be a grid. In this instance a platform, group box, or edit field is created at line 600, 670, or 740, respectively. Specifically, if the child of the current view object is determined to be a link at line 580, the following operations are performed: a platform is created at line 600; a search button is added to the newly created platform at line 610; this routine is called recursively at line 620, thereby adding controls to the platform definition; and the platform is added to the current form object (pFormObject) at line 630. If the child of the current view object is not a link according to the test at line 580, a test is made at line 650 to determine if the child of the current view object is a group. If the child is a group, a group box is created at line 670; this routine is called recursively at line 680, thereby adding controls to the group box; and the group box is added to the current form object (pFormObject) at line 690. If the child of the current view object is neither a link nor a group, it must be a single-valued, simple value view object (line 710). In this case, an appropriate routine is called at line 740 to create a control and add it to the current form object. A suitable routine for creating controls based on the data type of the simple value view component is set forth in LISTING L4. At line 780, a test is made to determine if the current view object is a multi¬ valued, simple value view object. By definition, such view objects cannot have children. If the current view object is a multi-valued, simple value view object, a routine is called at line 810 to add a column to the current form object (which must be a grid). A suitable routine for accomplishing this task is set forth in LISTING L3, and described next. The routine then terminates. LISTING L3 illustrates an exemplary routine for creating grid columns based on the data type of simple value view components. At line 60, a test is made to determine if the data type of pViewObject is a Boolean variable. If the data type is Boolean, a check box grid column is created and returned at line 70. Otherwise, an edit grid column is created and returned as shown at line 90. LISTING L4 illustrates an exemplary routine for creating controls in a platform based on the data type of a simple value view component. At line 60, a test is made to determine if the data type of pViewObject is a Boolean variable. If the data type is Boolean, a box is created and returned at line 70. Otherwise, an edit box is created and returned, as shown at line 90. Exemplarv Routines for Building Report Definitions The rules for creating default reports are not laid out in the detail that was given for default form generation above. Instead, exemplary routines for building a report definition, i.e., a hierarchy of report containers, in accordance with the invention are provided in LISTINGS L5-L6. The routine of LISTING L6 is similar to that in LISTING L2, and the report generation rules will be apparent from the routine and the following discussion. Those skilled in the art will appreciate how to generate the code necessary to display or print the report definitions described in the routine. When printing reports, one typically separates the data to be printed into a master section and one or more detail sections which show data related to the master data. A complete report is produced by selecting a set of objects, a.k.a. master records, and printing each of them followed by the appropriate detail records or objects. The routines presented in LISTINGS L5 and L6 generalize the process by allowing detail records to act as master records for further sets of detail records. At each level, master or detail, the data to be printed are represented by report items. Report items may also be collected and given a title. These collections can be used wherever a report item can, and print the title above the contained report items. The hierarchy of master and detail sections on a report is represented by objects of class MVReportContainer. Titles grouping report items are represented by objects of class SVReportContainer. Report items are represented by objects of class Reportltem. When these objects are created, they are passed a view object which carries information from the model. The report containers and report items can then obtain any needed information about data type, format, etc., from the view components. When presenting an object view as a report, the following mappings are used: (1) a root view object produces a multi-valued container and contents; (2) a multi¬ valued view object produces a multi-valued container and contents; (3) a single-value group produces a single-value container and contents; (4) a single-value object link produces a single-value container and contents; (5) a single-valued simple value produces a report item; and (6) as a special case, multi-valued simple values produce a multi-valued container and a single report item. The similarity of multi-value containers to grids, and single-value containers to platforms and group boxes, will be apparent, as will the similarity between report items and group columns or form items. Note that while the exemplary form creation rules elide single-value groups and links with a path maximum cardinality greater than one, these will generate single- value containers on a report. LISTINGL5 illustrates skeletal class descriptions showing the essential features of the C++ classes used in the routine of LISTING L6. Specifically, the classes created include: ReportContainer at lines 10-100; MVReportContainer (for multi-valued view components) at lines 110-160; SVReportContainer (for single- valued, non simple valued view components) at lines 170-220; and Reportltem (for simple value view components) at lines 230-280. Each container has a title area and a content area. The container MVReportContainer is used to specify the outermost formatting of a report. The multi-value and single-value containers dictate the formatting for multi-value and single-value view objects, respectively. Unlike the rules for form generation, the class of object created is not specific for different types of view objects, but instead is dependent solely on the maximum cardinality of the view object. It is noted that while the pseudocode does not show the data or implementation of the operations specified, these will be apparent to those skilled in the art. With reference to LISTING L6, a parameter called pViewObj that points to a "current" view object in an object view hierarchy is declared at line 20. When the routine is called for the first time, pViewObj will point to a root view object that is based on a semantic object for which a report is being created. Subsequent (recursive) calls will address lower level view objects. Line 30 declares a parameter called pContainer that points to a container that will hold the report definitions for the current view object. The types of containers that pContainer may point to include: a report (created for root view objects), a single-valued report container (SVContainer), or a multi-valued report container (MVContainer). At line 70, the title of the current container is set to the title of the current view object. The title will be the name of view object, unless a caption has been created by the user. Lines 80-100 define local variables "iter," pChild, and pNewContainer that the routine will use. The variable iter will be used to iterate across the contents of the current view object. During a loop bounded by lines 110-340, iter will return each child of the current view object, in turn. At line 130 a test is made to determine if the current child view object is an action item or action group. If it is, at line 140 the routine loops to line 110. At line 150, a test is made to determine if the child of the current view object that is under consideration is multi-valued, i.e., if it has a maximum cardinality that is greater than one. In accordance with the rules for report generation, multi-valued model components will generate a multi-valued container and contents, as shown in lines 150-210. At line 180, a new multi-value container is created. At line 190, this procedure is called recursively to define the contents of the container. At line 200, the new multi-valued container is added to the current container. Lines 220-340 are directed toward children that are based on single-valued link or group components only. At line 220, a test is made to determine if the child of the current view object is a link or a group. As dictated by the rules, in this case a single-valued container is created at line 250. At line 260, a recursive call is made to fill up the contents of the new container. At line 270, the new container is inserted into the current container. At this point, the else determination at line 290 refers to a child that must be a single-valued, simple value view object. At line 320, a report item is created and added to the current container. At line 350, a test is made to determine if the current view object is a multi¬ valued, simple value view object. By definition, such view objects cannot have children. If the current view object is a multi-valued, simple value view object, at line 380 a new report item is created and added to the current container. C++ Classes Tables T4-T27 illustrate the C++ classes that are used to represent the components listed in FIGURE 7. In each table, the data members of a class are listed in the left column and the data type in the right column. The description provided below will augment that of the '997 application. Thus, this description will focus only on the classes and data members/data types that have been added. In general, the changes include the addition of data members to the previously defined classes to support the creation of object views. With reference to Tables T4-T21, the data members that have been added to classes described in the '997 application include: DATA MEMBER DESCRIPTION Allow Delete Specifies whether a user is allowed to delete rows in a grid or records shown on a form that is ultimately created for a view component; in the group template, group component, group view, subtype view, and subtype group view classes. Allow New Specifies whether a user is allowed to create rows in a grid or records shown on a form that is ultimately created for a view component; in the object link template, group template, group component, object link, object link view, group view, subtype view, and subtype group view classes. Allowed Action Specifies whether a user can modify a field on a form ultimately generated from a simple value template; in the simple value template, simple value component, and simple value view component classes. Connect/Disconnect Specifies what a user is allowed to do on a Power platform that is generated from an object link template; in the object link template, object link component, and object link view classes. Help ID Enables the object model to track user- supplied help files; located in each of the classes except the object model class. Recompute Expression Describes the computation used to produce a value; in the simple value template, simple value component, and simple value view classes. Source An indication of whether a user is to enter data (source is set to user), data is to be computed by the run-time system (source is script), or a combination of the two (source is both); in the simple value template, simple value component, and simple value view component classes. Status Bar Text A text string for providing instructions to a user on a form; in the simple value template, simple value component, and simple value view component classes. View Components An unordered collection of pointers to view components based upon this component; in the simple value, group, object link, parent, subtype, and subtype group component classes. Views An unordered collection of pointers to root view objects; in the semantic object class. Action Items and Action Groups Revisited Of the elemental building blocks used in semantic object modeling in accordance with the invention, only semantic objects; has-a type components (i.e., simple value, object link, and group); and is-a type components (i.e., parent, subtype, and subtype group) were described in the '997 application. The following describes the creation and insertion of action item and action group components into an object model. As was described in FIGURES 5A-5D and accompanying text, action items and action groups define buttons or menus on forms created from semantic objects that perform desirable functions. As with other components, all action items and action groups are based upon some corresponding template. The design tool provides the user with a predefined list of typical action templates that may be used with a semantic object. Exemplary action templates include: arrange icons, copy, cut, paste, delete field, delete record, find, open form, print report, and run script. Exemplary action group templates include: forms, help, record, reports, view, and window. In addition, a user can create action item or group templates. The C++ classes directed to action item and action group components have been added as an extension to the object model described in the '997 application. The classes are set forth in TABLES T22-T27. A listing of action type values is shown in TABLE T28. The relevant data members that were not included in the '997 application or in the discussion above are set forth below: DATA MEMBER DESCRIPTION Action Operand View A pointer to an object view which is the subject of the action, if appropriate to the action type. An action with an action type of "Open Form" would have a pointer to the object view for the form to be opened as its Action Operand View. Action Type The action to be performed, such as those listed and described in FIGURE 32. Allow Add/Delete Specifies whether a user is allowed to add or delete records displayed on the form opened by this action (only used with Action Type of "Open Form"). Allow Update Specifies whether a user is allowed to update records displayed on the form (only used with Action Type of "Open Form"). Checked Sets default state of a menu item generated from the action item to checked (if yes) or unchecked (if no). Derived Components An unordered collection of components that are created using a given template. Enabled Sets default state of a menu item or button generated from the action item to enabled (if yes) or disabled (if no). Referencing Templates An unordered list of group templates which have a pointer to the template in their contents collection. Search View A pointer to an object view used to display the results of a query for a form, or used to obtain a query for a report. Visible Sets default state of a button generated from the action item to visible (if yes) or invisible (if no). FIGURE 16 illustrates exemplary steps that may be taken by the design tool 50 to create a template for an action item. The action item "Open Form" is used as an example. Other action items follow the same format, but may have more or less information in the template depending upon the action that is being invoked. At block 800, sufficient memory is allocated for the new action template. At block 801, the new template is assigned a unique integer identifier. The user is prompted to enter a name for the template at block 802. If no name is provided, the system gives the new template a default name descriptive of the action, e.g., "Open Form." At block 803, a test is made to determine if the name of the template is unique among all templates within the object model. If not, a numeric suffix is added to differentiate the name of the new template at block 804. Once the name of the template is distinguished from all other templates in the object model, or if the name was unique in the first place, the accelerator key of the action template is initialized to "None" at block 806. The accelerator key property allows a user to choose a key sequence which invokes the action. At block 807, the action associated with the action template is initialed to "Open Form." The action target is then initialized to "None" at block 808. Some actions require the user to specify a target for implementing the action, which will be an object view. For example, the Open Form action item requires a user to select a form object view. At block 810, the caption property of the action template is initialized to an empty string. The caption property provides an alternative field title to be used on a form produced by an application program accessing the database whose schema is defined by the object model. The description property of the action template is initialized as an empty string at block 810. The enable property, which allows a user to enable or disable a control generated from the action, is then initialized to "yes" at block 812. At block 813, the help ID property is initialized to "0." The help ID property is used on run-time to connect to user-defined help files. At block 814, the "form access permissions" are initialized to default. Form access permission is a collective term for grouping of permission to add, permission to delete, and permission to update properties. The "permission to add" property determines whether or not a user of the form can add new data to the database; the "permission to update" property determines whether a user can update data in the database; and the "permission to delete" property determines whether a user can delete data from the database. For each of these permissions, the setting can be yes or no. The default for each action item is typically set to yes. At block 815, the status bar text for the action item is set to a text string that describes the function of the action. In the case of the "open form" action item, the text would read: "Opens the form for data entry and searching." At block 816, the derived components property list for the action template is initialized as an empty, unordered collection of pointers to components that are derived from the newly created action template. The routine then terminates. A second action item property that is not mentioned in the "open form" action, but that is advantageous, is called "query form." The "query form" action item property allows a user to choose a form that is displayed prior to the printing of a report. This form will then be used to define a query that will dictate the contents of the report. While creating and modifying an object model, a user can add action items to semantic objects in the model by selecting, dragging, and dropping an action template from the template manager into the semantic object. Once an action template is dropped into a semantic object, the system creates a corresponding action item (or action group). An exemplary routine for creating action items is set forth in FIGURE 17. After the action item is created, the design tool immediately inserts it into the semantic object using the routines shown in FIGURES 19 and 20, described below. With reference to FIGURE 17, the design tool first gets a pointer to the corresponding action template at block 820. Next, sufficient memory is allocated for the new action item at block 821. At block 822, the action item is assigned a unique integer identifier. At block 823, the accelerator key, action, action target, caption, description, enable, help ID, name, permission to add, permission to delete, permission to update, and status bar text properties are initialized from the corresponding property in the action template that is being used to create the action item. If at any time the user desires to change any one of the properties of the action item as they apply only to the semantic object in which the component is placed, the user may do so using the property sheet shown in FIGURE 2B and described above. The container property is set equal to NULL at block 824. When the action item is inserted into a semantic object, the contained pointer will be set equal to the address of the containing semantic object. If the action item is placed in a nested action group, the container property will be set to point to the innermost action group that contains the action item during the routine in which it is inserted. At block 826, the base template pointer is set equal to the address of the action template from which the action item was created. At block 828, a pointer to the newly created action is added to the list of the derived action item components maintained by the corresponding action template. The derived component list is used by the design tool to effect changes to a property of all components based upon a template if a user changes the property in the corresponding template. FIGURE 18 illustrates an exemplary routine for creating an action group template in accordance with the invention. First, sufficient memory is allocated for the new action group template at block 830. The action group template is then assigned a unique identifier at block 831. At block 832, the user is prompted for a name for the action group template. If no name is provided, the system will use the default name "action group." At block 834, a test is made to determine whether the action group name is unique among all groups in the object model. If not, a numeric suffix is added to differentiate the action group name from related names, shown at block 835. Once the name of the template is distinguished from all other templates in the object model, or if the name was unique in the first place, the caption property of the action template is initialized to an empty string at block 836. At block 839, the description property of the action template is initialized as an empty string. At block 840, the enable property is initialized to "yes." The help ID property is then initialized to "0" at block 841. At block 842, the status bar text for the action item is set to a text string that describes the function of the action. At block 844, the contents property of the action group is initialized as an empty, ordered collection of pointers to the templates that are contained within the action group template. At block 846, the derived components list is initialized as an empty, unordered collection of pointers to action groups that are derived from the newly created action group template. The routine then terminates. Action group templates will usually have other templates added to then- contents list before being used in the object model. These additions may be performed using an exemplary routine defined in FIGURES 38 A and 38B. Once a new action group template has been created, the user can create a corresponding action group component in one or more semantic objects by selecting the action group template, dragging, and dropping it into the boundaries of a semantic object. Once an action group template is dropped within a semantic object, the design tool creates a corresponding action group component according to the blocks shown in FIGURE 19. With reference to FIGURE 19, to create an action group it is first necessary to get a pointer to the corresponding action group template, as shown at block 848. At block 850, sufficient memory is allocated for the new action group component. The action group component is assigned a unique identifier at block 852. At block 854, the action group's caption, description, enable, help ID, name, and status bar text properties are initialized from the properties of the corresponding action group template. At block 856, the container pointer is set equal to NULL. When the action group component is inserted into a semantic object, the container pointer is set equal to the address of the semantic object or the action group component in which the new action group component is logically included. Exemplary routines for performing this task are set forth in FIGURES 20 and 21A-21B. If the action group component is nested in another action group component, the container pointer will be set to point to the innermost action group. Next, the components that are defined by the contents list of the action group template are created. For each template in the contents list, the design tool creates a new component and places a pointer to the new component in the contents list for the new action group component, as shown at block 858. At block 860, a pointer to the new action group component is placed in the corresponding group template's list of derived components. FIGURE 20 is an exemplary routine for updating the object model when a user has inserted a new component into a semantic object (i.e., the current semantic object). At block 862, the design tool gets a pointer to the new component being inserted, be it an action item, action group, or other type of component. At block 864, a test is made to determine whether the user is attempting to insert a parent component that is derived from a template, which is based upon a semantic object that is a subtype of the current semantic object, or that is based upon the same template as a parent component that the semantic object already contains. At block 866, a test is made to determine whether the user is attempting to create a subtype component created from a template that corresponds to a semantic object, which is a parent of the current semantic object, or is based upon the same template as a subtype component that the current semantic object already contains. If such an insertion is detected at either block 864 or 866, an appropriate error message is produced at block 870, and the insertion is not allowed. Assuming that the user is not attempting an illegal insertion of a component into a semantic object, a pointer to the newly added component is included in the current semantic object's contents list at block 872. Next, the container pointer of the inserted component is updated to point to the current semantic object at block 874. At block 876, the design tool ensures that the names of the newly added component and all the component's contents, if a subtype or action group, are unique within the semantic object. If any name is not unique, a numeric suffix is added to the name to differentiate it. The routine then terminates. In the course of developing an object model, a user may wish to add an action item or action group component to an action group. This change is accomplished by selecting or creating such a component from a template dropping it into the action group component. FIGURES 21 A and 2 IB illustrate an exemplary routine for adding a component to an action group. At block 878, a test is made to determine if the component being added to the group is an action item or an action group component. If the component is not one of these types, an error message is produced at block 880 indicating that the insertion is not allowed. Assuming that the component can be added to the action group component, a pointer to the new component is added to the action group's ordered contents list at block 882. At block 884, the container pointer of the inserted component is changed to the group component that contains the new component. At block 886 a test is made to determine if the name of the new component is unique among the components already present in the action group. If not, a numeric suffix is added to differentiate the name at block 887. Once this is accomplished, or if the names of the components in the action group were already unique, a test is made at block 888 to determine if the group component into which the new component has been inserted is the only group that is derived from the corresponding group template. If so, then a pointer to the template of the added component is added to the contents Ust of the group template at block 889 and the routine terminates. If more than one group has been created from the corresponding group template, a new group template is created at block 890. The contents list of the new group template is initialized to include the templates of all the member components, including the new member component, at block 891. At block 892, a test is made to determine if the current group is contained within another group, i.e., in a "container group." If the current group is not contained within another group, the routine terminates. Otherwise, a test is made at block 893 to determine whether the container group is the only group derived from its corresponding template. If the container group is not the only group derived from its corresponding template, a new group template is created at block 894. At block 895, the contents list of the newly created group template is initialized to include pointers to all the member components. Once this is accomplished, the routine terminates. If, according to the test at block 893, the container group is the only group derived from its corresponding template, the contents list of the corresponding group template is updated to include the template of the newly added component at block 896. The routine then terminates. FIGURE 22 illustrates an exemplary routine for inserting an action item template or action group template into an action group template. At block 900, a test is made to determine if the user is attempting to add a template whose contents list already includes the group template into which the new template is being inserted. If the answer is yes, an error message is presented at block 902, indicating that the insertion is not allowed because it represents a recursive relationship. Assuming that the template can be added to the group template, a pointer to the newly added template is appended to the contents list of the group template at block 904. As indicated above, each template includes a containers list of the templates in which it is included. At block 906, a pointer to the group template is added to the containers list of the newly inserted template. At block 908, the design tool considers each component in the derived components list maintained by the group template and creates a new component from the newly inserted component template and inserts it into the derived component. Therefore, each component within the semantic object model is updated to reflect the template newly added in the group template. The routine then terminates. Run Time View Creation A run-time view hierarchy is a data structure that is used when running forms and reports. The structure of a run-time view hierarchy is related to the structure of semantic objects, but is separate therefrom because it incorporates information about the database schema not represented in the object model. As described above in FIGURE IA, there are two types of run-time view hierarchies: semantic object based run-time view hierarchies, called canonical "run-time views," and run-time view hierarchies based on object views, called "form views." As with object views, there may be many run-time view hierarchies based on a single semantic object. In general, each form and each report will have a separate form view upon which it is based. To be more specific, a run-time view hierarchy is a hierarchy of "view elements," where each view element is founded from either a semantic object, a model component in the object model, or a view object. A run-time view hierarchy stems from a root view element, defined as a view element based on a semantic object or a root view object. As is described in detail below, view elements are containers that hold information necessary for running forms and reports. For example, a view element corresponding to a link will include information about the semantic object coupled to the link. The type of information held in any particular view element is determined by the object type, e.g., simple value. What is contained in a run-time view hierarchy is dictated by the rules that are set forth and discussed below. The classes of a run-time view hierarchy include: (a) view element and (b) group view element. View elements are generated in connection with simple value components and simple value object view components, as well as database columns in the schema not otherwise represented in the object model. Group view elements are generated in connection with semantic objects, all model components except for single-valued simple value components, and all view objects except single-valued simple value view components. Canonical Run Time View Hierarchies The following rules govern what is included in a canonical run-time view hierarchy. The object model 262 illustrated in FIGURE 8 will be used throughout the remainder of this discussion. Semantic Object: (1) Semantic objects produce a root view element that includes view elements based on model components directly contained by (topmost level) the semantic object. For example, the root view element order will contain view elements representing: order number, order date, customer, line item, subtotal, tax, and total. Of these, customer and line item are group view elements; the remaining elements are simple view elements. For a description of the data held by root view elements, see the group view element class described in LISTING 7B and accompanying text. (2) In addition, a root view element will include view elements representing the surrogate key, if any, for the table generated for the semantic object, and may include view elements based on foreign keys used to carry link information between semantic objects. For example, the root view element order will contain the surrogate key ID_ and foreign key CUSTOMER_ID_FK, shown in lines 430 and 390, respectively, of LISTING L74. Simple Value Components: Simple value model components produce either a single view element, or a group view element containing two or three view elements, depending upon the cardinality and ID status of the component. Single-valued simple value components produce a view element only. Multi-valued simple value components produce a group view element associated with the table generated for the component. Group view elements based on multi¬ valued simple value components that are ID unique will contain a view element for a foreign key to the parent table group and a view element for the data represented by the component. Group view elements based on multi-valued simple value components that are not ID unique contain these, and in addition, a view element that represents a surrogate key for the table. For a listing of the data held by non-group view elements, see the view element class described in LISTING L7A and accompanying text. Group Components: Single-valued group components, including subtype groups, produce a group view element that contains view elements generated from the components in the group. Multi- valued group components will contain an ID, foreign key and whatever is generated from the group, including data groups. Consider the group component line item; it will contain ORDER ID_FK, ITEM D FK, item, unit cost, quantity, and extended price, and ID_. For a listing of the data held by group elements, see the group view element class described in LISTING L7A and accompanying text. Object Link Components: Object link components include object links, parent links, and subtype links. An object link component will generate a group view element based on the referenced semantic object and containing those view elements necessary to represent the primary key of the table generated for the referenced semantic object. In addition, one or more view elements representing a foreign key carrying the relationship are created. The foreign key view elements relate the current table group to the table group generated for the container of the object link component's pair component. Which group view element contains the foreign key view elements is determined during schema generation, and indicated by the schema. A group view element to contain the foreign key view elements will be created if necessary, as described in LISTING LI 5 and the accompanying text. The rules for creating view elements representing object links are set forth in greater detail in LISTING L9 and L10 and accompanying text. For a listing of the data held by group elements, see the group view element class described in LISTING L7B and accompanying text. LISTING 7A illustrates an exemplary class definition for the C++ class "ViewElement". Class ViewElement defines the base class for the worker classes of run-time view hierarchies. This base class defines accessors for some data that only make sense in derived classes, e.g., group view elements, as well as accessors and operations useful in the base class. In general, simple (non-group) view elements hold data, i.e., which may be user data or system data such as primary or foreign keys. Group view elements provide aggregation and iteration services to clients of the run¬ time view. Lines 190-290 define enumerations useful in the operation of view elements. The "roles" enumeration indicates how a view element, or group view element, is used, i.e., its role in the run-time view hierarchy. The unnamed enumeration defined on line 290 is used to tell the view element if updated information is acceptable when calling member functions which provide values or status of database data items. Lines 300-470 declare various constructor functions for view elements; each of these is described in the text accompanying its listing. Lines 500-510 both provide for the creation of a ViewElementlter which provides any contained ViewElement objects, one at a time. Since base class ViewElements do not contain any other view elements, the iterator object returned is always empty when these functions are invoked on the base class. Lines 530-630 define various useful informational functions. All of these functions can be computed by examining the role of the view element. The functions IsGroupO and IsColumnO are inverses, allowing the user to check if a particular view element is a group view element or simply a view element. The function IsTableO, and its alias IsTableGroupO, will return true if the role is ATTR TABLE, X TABLE, or SO TABLE. In contrast, the function IsIntersectionTableQ merely checks to see if the role is X T ABLE. The function IsLink() returns true for any view element having a role of SO TABLE which also has a parent group view element. It should be apparent that any view element with a role of SO_TABLE will in fact be class Group ViewElement. Lines 650-690 provide access to information about the view element hierarchy and the key structure of the tables with which it is associated. The functions PrimaryKeyO and ForeignKeyO are virtual, with only vacuous implementations in the base class, i.e., they return NULL. Lines 700-720 define functions used in construction of run-time view hierarchy or in creating SQL statements. These are described in the text accompanying the listings for each function. Lines 740-780 declare functions which provide read and write access to the values contained by a view element at run time, as well as information about the values. The implementation of these functions is readily apparent. Line 790 declares the function CopyKeyO which will copy the current value of the object pointed to by the keyPair member variable to the current view element, unless the current view element is non-NULL, or has a NULL keyPair; in these cases, a suitable error is returned. Lines 800-810 provide means to set and retrieve a predicate value associated with the current view element. This value is used when building queries, as can be seen in LISTINGS L48-L57 and the accompanying text. Line 820 defines the function SubQueryPredicateO, which is shown in LISTING L53 and described in the accompanying text. Lines 830-990 declare accessor functions for some of the member variables declared on Lines 1010-1240. These are all trivial functions which simply return the appropriate data values; their implementation will be apparaent to one skilled in the art. The member variables are defined as follows: objectID and viewObejctID are assigned when the object is constructed, indicating the base model object and base view object for the view element. Either or both of these may be zero. The data members minCard, maxCard, allowedAction, idStatus, valueType, dataSource, initialValue, and recomputeExpresion carry values from the object model, if available, depending on the constructor used. See the constructor listings for further details. The data members name, maxLength, scale, logicalLength, dataType, and dbDataType carry values from the schema, if available, as appropriate. The data members role, parent, parentTableGroup, pColumn, and pModelObject are set according to the specific constructor used. The data member keyPair is set by SetKeyPairQ, if invoked during run-time view construction. LISTING 7B illustrates an exemplary class definition for the C++ class "Group ViewElement". Group View Elements provide aggregation and iteration services to clients of the Runtime View. They also provide cursor-like behavior when created in association with a table in a database schema definition. Lines 120-240 declare various constructor functions for group view elements; each of these is described in the text accompanying its listing. Lines 270-280 both provide for the creation of a ViewElementlter which provides any contained ViewElement objects, one at a time. The iterator object returned can be used to obtain a pointer to each view element on a particular Group View Element's contents list, in turn. Lines 300- 320 return values from member variables declared on lines 1200, 1210 and 1180 of this listing; these values are set when the Group View Element is constructed. Lines 330-360 provide access to information about the View Element hierarchy and the key structure of the tables it is associated with. PrimaryKeyO returns the value the pPrimaryKey member variable. ForeignKeyO returns the result of using the supphed pointer as a key in the foreignKeys hash table. Either or both of these functions can return NULL; both of them are sure to return NULL if the Group View Element used to call these functions is not associated with a table in the database schema. Line 380 declares the member function ValidatateCountsAndCardsO, which is shown in LISTING L42, and described in the accompanying text. Lines 400-580 declare functions used to perform database queries using a runtime view hierarchy. These functions are shown in LISTINGS L46-L57, and described in the accompanying text. Lines 600-710 declare functions which provide cursor behavior for a Group View Element. The operation of these functions is generally obvious; GetPairCountO returns the number of instances of a Semantic Object connected to the current object instance, and is used to determine if an object is available for connection. NewRowO adds a blank (all-NULL) row to the current set. This is used when extending the set by insertion (prior to calling Value() on the various View Elements contained in the group), or by selection of a queried row (prior to copying the contents of the queried row with CopyQueryRowO). CopyQueryRowQ copies the row at the current position in a query result set to the current position in the editable result set. Lines 720-860 declare functions used to effect changes to a database. These functions are shown in LISTINGS L37-L45, and LISTINGS L66-L71, and described in the accompanying text. Lines 880-1050 declare functions used in the construction of complete runtime views. These functions are shown in LISTINGS L14-L36, and described in the accompanying text. Lines 1070-1140 declare accessor functions for some of the member variables declared on Lines 1170-1290. These are all trivial functions which simply return the appropriate data values; their implementation is obvious. The member variables are defined as follows: connectPower, disconnectPower, fDeleteAllowed, fNewAllowed, minCount, maxCount, pairMinCard, and pairMaxCard carry values from the object model, as set by the particular constructor used. See the constructor listings for further detail. The data member pTable is set by the various constructors as appropriate. The data member pPrimaryKey is set by AddPrimaryKeyO; the data members relatedTables and foreignKeys are added to by calls to AddRelatedTableO; and the contents member variable is populated by the process of building a run-time view. Both versions of DefineRuntimeViewO will demonstrate this process. LISTINGS L8-L12 are exemplary pseudocode routines for constructing view elements and group view elements that will be invoked by the routine described in LISTING L14. With reference to LISTING L8, the block defined by lines 60-260 show initializers for data members of the view element class. In essence, each data member is initialized to one of the following: a constant value, a value supplied by the base component object, or a value supplied by the data column definition. At lines 280-300, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if it is a table, or to the containing group view element's parentTableGroup if it is not. At the block bounded by lines 310-350, a test is made to determine if the parent table group is based on the same model component as that on which the object being constructed (this object) is based. If so, this view element must represent the data column for a multi-valued simple value component. The design tool does not allow NULL values for such columns, and thus the minimum cardinality for the current view element is set to one. The routine then terminates. LISTING L9 is a pseudocode constructor that will be invoked by the routine illustrated in LISTING L10. Specifically, the constructor initializes the data members listed in lines 60-240 to constant values, to values obtained from the supplied model object, or from a table in the schema. At lines 260-280, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if the containing group view element is a table, or to the containing group view element's parent table group if it is not. The routine then terminates. LISTINGL10 illustrates an exemplary pseudocode routine for initializing (constructing) a group view element that is associated with a table in the schema. Specifically, at line 60 the constructor of LISTING L9 is invoked to initialize the base view element class portion of the current group view element. The block bounded by lines 70-150 initialize member variables of the group view element object to default or supplied values. At line 170, a test is made to determine if the current group view element has no parent or if the model component on which this group view element is based is a link. If so, at line 190, the member variable "role" is set to indicate that the associated table was generated from a semantic object. At line 200, a test is made to determine if the current group view element has a parent. If the current group view element does have a parent, it must represent a link. In this case, the data members listed in lines 220-270 are initialized with values obtained from the base model component. A block defined by lines 300-450 is entered if the base object of the current group view element is a multi- valued group or simple valued component. In this case, at line 320 the role is set to indicate that. At line 330, a test is made to determine if the base object is a group. If so, the data members listed at line 350-380 are initialized to values from the model object. If the current group view element is based on a multi-valued simple value, the data members listed in lines 420-430 are initialized as shown. The routine then terminates. LISTING LI 1 illustrates an exemplary constructor invoked by the routine of LISTING L12 and takes into account single-valued groups. Specifically, the constructor initializes the data members listed in lines 50-220 to constant values, or to values obtained from the supplied model object. At lines 240-260, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if it is a table, or to the containing group view element's parent table group if it is not. The routine then terminates. LISTING L12 illustrates a pseudocode routine for initializing a single-valued group view element. Specifically, line 50 invokes the view element constructor of LISTING LI 1. Lines 60-140 list the data members, which are initialized to constant values or values obtained from the associated model component. At line 160, the member variable role is set to indicate that this group view element represents a single-valued group. The routine then terminates. LISTING LI 3 illustrates an exemplary routine for creating a set of canonical views associated with a particular object model. At line 20, a parameter "theModel" is declared which references an object model for which run-time views are to be created. At line 50, a variable "iter" is initialized from the model as an iterator on the collection of all semantic objects in the model. Lines 60-70 declare variables used in the iteration. Line 80 declares and initializes a reference to the schema associated with the object model. During the block bounded by lines 90-130, the variable pSO will be set to a pointer to each semantic object in the model, in turn. At line 110, a new group view element is created based on the semantic object pointed to by pSO with a parent specified as NULL and associated with the table pointed to by the parameter returned by "theSchemaXookup(pSO)," which looks up the semantic object in the schema and returns a pointer to a table object representing a database table generated from the given semantic object. At line 120, the routine DefineRunTimeView is invoked with a pointer to the current semantic object and the schema as parameters. This routine is described next. LISTING L14 illustrates an exemplary routine for creating canonical run-time views in accordance with the invention. A knowledge of relational database schemas and their underlying tables is presumed. At line 20, a parameter called pModelObj is declared that points to a "current" model object in an object model. When the routine is called for the first time, pModelObj will point to a root semantic object which is the base model object for the current group view element. Subsequent (recursive) calls will address model components contained within the semantic object. At line 30, a parameter called "theSchema" is declared and will be used to provide information about the relational database schema generated for the current object model. Lines 60-100 define local variables "iter," pChild, pVE, pGVE, and pTable that the routine will use. The variable iter will be used to iterate across the contents of the current model object. During a loop bounded by lines 480-850, iter will return each child of the current model object, in turn. At line 110, a test is made to determine if the current group view element is associated with a table in the schema. If the current group element is associated with a table in the schema, a routine titled "AddPrimaryKey" is called at line 130 to add a view element representing the primary key of the table to the current group view element. At line 140, a test is made to determine if the table associated with the current group view element is an intersection table. If so, at line 160, the schema is consulted to determine a pointer that will point to a table generated from the current model object's referenced semantic object. A new group view element is created at line 170 based on the current model object (pModelObj) having a parent specified as the current group view element (this) and associated with the table pointed to by pTable. At line 180, a pointer to the newly created group view element is added to the contents variable, which is a member variable of the current group view element. At line 190, a call is made to this routine on the newly created group view element with the current model object (pModelObj) and the schema of the object model as parameters. A routine titled "AddForeignKey" is called at line 200 to add a view element representing the foreign key between the intersection table and the semantic object table generated from the model object's referenced semantic object. At line 210, a view element representing the foreign key between the intersection table and the intersection table's parent table group is added to the current group view element. At line 220, the routine terminates. At line 240, a test is made to determine if the current group view element is contained within another group view element. At line 260, a test is made to determine if the table associated with the current group view element was generated from a semantic object. If the current group view element is contained within another group view element and if the table associated with the current group view element was generated from a semantic object, at line 290 a local variable called pPairObj is declared as a pointer a model object and initialized to the current model object's pair object. At line 300, a variable called pSO is declared as a pointer to a model object and initialized to the current model object's referenced semantic object. At line 310, a variable called pLinkParent is declared as a pointer to a group view element and is initialized to the current group view element. At 320, a test is made to determine if the current model object's referenced semantic object directly contains the current model object's pair object. If it does not, a function titled CreateParentGroup is called to create and return a pointer to a group view object based on the model object that does contain the current model object's pair. An exemplary routine for performing this function is set forth in FIGURE LI 5. At line 360, a test is made to determine if the table associated with the model object based on the container of the current model object's pair contains the foreign key that carries the relationship represented by the current model object and its pair. If so, the routine AddForeignKeyO is called to add the appropriate view elements to the group view element based on the container of the current model object's pair. At line 400, the routine terminates. At line 420, a test is made to determine if the table upon which the current group view element is based carries the foreign key relating it to the current group view element's parent table group. If so, at line 440 the routine AddForeignKeyO is called to add the appropriate view elements to the current group view element. The loop beginning at line 480 examines each of the children of the current model object, in turn. At line 500, a test is made to determine if the child of the current model object (current child object) is a link. If the current child object is a link, at line 530 the schema is consulted to determine if a table has been generated for the current child object. At this point, if a table has been generated it will necessarily be an intersection table. Intersection tables are considered to be based on both link objects related to the table, i.e., the contents of the table will be reviewed from either side of the link. If an intersection table is not found, at line 550 the schema is consulted to obtain the table generated for the child's referenced semantic object. A new group view element is created at line 560 based on the current child object (pChild) having a parent specified as the current group view element (this) and associated with the table in the schema pointed to by pTable. At line 570, a pointer to the newly created group view element is added to the contents member of the current group view element. At line 580, a call is made to this routine on the newly created group view element with the current child model object (pChild) and the schema of the object model as parameters. At line 590, a test is made to determine if the table associated with the current group view element contains a foreign key representing the relationship between the current child's referenced semantic object and the table. If so, a routine titled AddForeignKeyO is called at line 600 to add the appropriate view elements to the current group view element. At line 620, a test is made to determine if the current child object is multi¬ valued. If so, a new group view element is created at line 650 based on the current child object (pChild) whose parent is the current group view element (this) and associated with the table pointed to by the parameter returned from the schema by Lookup(pChild). At line 660, the newly created group view element is added to the contents member variable of the current group view element. At line 670, a call is made to this routine on the newly created group view element with the current child model object (pChild) and the schema of the object model as parameters. At line 690, a test is made to determine if the current child object is a group. In this case, it must be a single-valued group. If so, a test is made at line 720 to determine if a group view element already exists in the current group view element that is based on the current child object. If not, a new group view element is created based on the current child object and having a parent that is specified as the current group view element. At line 750, a pointer to the newly created group view element is added to the contents member variable of the current group view element. A call is then made to this routine on the newly created or preexisting group view element with the current child model object (pChild) and the schema of the object model as parameters, as indicated at hne 770. At line 790, a test is made to determine if the current group view element already contains a view element based on the current child object. If not, at line 820 a new view element is created based on the current child object having a parent specified as the current group view element and associated with a column in the table associated with the current group view element that is based on the current child object, i.e., returned by TableO-»Lookup(pChild). At line 830, the newly created view element is added to the contents member of the current group view element. Line 850 concludes the loop that was started at line 480. Lines 860-910 take into account view elements that represent data columns in the table generated by a multi-valued simple value model component. Specifically, at line 860 a test is made to determine if the current model object is neither a group nor a link, and if the current group view element is a table group. If all of these conditions are present, a new view element is created at line 890 based on the current model object (pModelObj) and associated with a column in the table associated with the current group view element that is based on the current model object, i.e., returned by Table0-»Lookup(pModelObj). At line 900, a pointer to the newly created view element is added to the contents member variable of the current group view element. The routine then terminates. LISTING LI 5 illustrates an exemplary routine in accordance with the invention that creates and returns a group view element based on the model object that contains the model object specified by pTargetModelObject. At line 30, a parameter called pTargetModelObject is declared that points to a current model object in an object model that contains a target model object. At line 40, a parameter called "theSchema" is declared and will be used to provide information about the relational database schema generated for the current object model. At hne 70, a variable pNextModelObj is declared and initialized to the model object which contains the target model object. At line 80, a pointer variable pNextGVE is declared. At line 90, a test is made to determine if the model object containing the target model object is the base object of the current group view element. If so, a pointer to the current group view element is returned. Lines 110- 120 will repeat until the model object pointed to by pNextModelObj is directly contained within the model object upon which the current group view element is based. At line 180, a test is made to determine if the schema contains a table based on the model object pointed to by pNextModelObj. If so, at line 150 a new group view element is created based on the model object pointed to by pNextModelObj having a parent specified as the current group view element and associated with the table pointed to by pTable. At line 160, the function AddPrimaryKey is invoked on the new group view element. At line 170, the routine AddForeignKeyO is called on the new group view element. The else determination at 190 will be reached if there was not a table generated for the model object pointed to by pNextModelObj. In this case, a new group view element is created based on pNextModelObj with the parent specified as the current group view element. At line 230, the group view element pointed to by pNextGVE is added to the contents list of the current group view element. At line 240, a test is made to determine if the target model object is directly contained within the model object upon which the current group view element is based. If not, this routine is called on the group view element pointed to by pNextGVE, and the result is assigned to pNextGVE. At line 280, the current value of pNextGVE is returned. LISTING LI 6 illustrates an exemplary routine for creating primary key view elements associated with a table and adding them to the table group view element. At line 40, a variable pPK is declared and initialized to a pointer to a primary key data column of the table associated with the current group view element. Primary keys may or may not have model objects associated with them, depending upon whether or not surrogate keys are generated for the table. If surrogate keys have been generated for a table, no model object is associated with the table's primary key. At line 50, a variable called pModelObj is declared. At line 60, a pointer to a view element entitled pVE is declared. At line 70, a test is made to determine if there is a model object associated with the primary key of the table. If so, a pointer to the model object is assigned to pModelObj and a block defined by lines 80-170 is executed. At line 90, a test is made to determine if the model object is a group. If so, at line 110, a new group view element is constructed based on the group model object, with a parent specified as the current group view element, and associated with the (group) data column object pointed to by pPK; a pointer to the new group view element is assigned to pVE. A suitable constructor for accomplishing this task is set forth in LISTING LI 9, and described in the accompanying text. If the model object is not a group, a new view element is created based on the model object with a parent specified as the current group view element and associated with the (simple) data column object pointed to by pPK, as indicated at line 150. A suitable constructor for accomplishing this task is set forth in LISTING L8, and described in the accompanying text. If there is no model object associated with the primary key, a new view element is created with the parent specified as the current group view element and associated with the primary key pPK. A suitable constructor for performing this task is illustrated in LISTING LI 8, and described in the accompanying text. At line 220, a pointer to the newly created view element is added to the contents variable, which is a member variable of the current group view element. The routine then terminates. LISTING LI 7 illustrates an exemplary routine for adding view elements which represent the foreign key between the current group view element and the group view element specified by a parameter entitled pReferencedGroup. The object giving rise to the relationship is specified by the variable pLink. At line 70, the table associated with the current group view element is consulted to obtain the foreign key columns representing the relationship specified by pLink; and a pointer to this data column is assigned to pFK. At line 90, a test is made to determine if the foreign key data column is a group data column. If it is, a new group view element is created based on pLink with a parent specified as the current group view element and associated with the data column specified by the variable pFK. The address of this new group view element is assigned to pVE. If the foreign key represents a single data column, a new view element is created based on pLink with a parent specified as the current group view element and associated with the data column specified by the variable pFK, as indicated at line 150. At line 170, a routine called SetKeyPair is invoked on the newly created view element to initialize the key pair member variable(s) of the view element or group view element. Suitable routines for performing this task are illustrated in LISTINGS L20 and L21, and described in the accompanying text. At line 180, the routine AddRelatedTable is invoked on the current group view element to remember that the current group view element has a relationship to the referenced group view element and that the foreign key for this relationship is pVE. A suitable routing for performing this task is illustrated in LISTING L23, and described in the accompanying text. At hne 190, the same function is invoked on the referenced group view element to inform it of its relationship with the current group view element. At line 200, a pointer to the newly created view element is added to the contents member variable of the current group view element. LISTINGL18 illustrates an exemplary routine for constructing a view element not based on a model object, but associated with a data column object. Lines 50-290 initialize member variables for the view element class. The member variables are initialized to either constant or values supplied by the column object, as shown. At lines 310-330, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if the containing group view element is a table, or to the containing group view element's parentTableGroup if it is not. The routine then terminates. LISTING LI 9 illustrates an exemplary routine for creating a group view element based on a model object and associated with a group data column. At line 60, the constructor for the base view element class is invoked. A suitable routine for performing this task is shown in LISTING L8, and described in the accompanying text. At lines 70-150, member variables of the group view element class are initialized to appropriate constant values. At line 170, the member variable "role" is set to indicate that this group view element represents a group of columns, as opposed to a table. Lines 180-250 set member variables to values supplied by the parameters as shown. At hne 260, an iterator "iter" is defined and initialized to the columns within the supplied group data column. At line 270, a pointer to a data column entitled pFKPart is declared. At line 280, a pointer to a view element entitled pVE is declared. During the loop defined by the lines 290-400, the variable pFKPart is assigned to each of the columns determined by iter, in turn. At line 310, a test is made to determine if the current group view element is associated with a primary key. If so, at line 330, a new view element is created based on the model object which caused the data column pointed to by pFKPart to be generated, having a parent specified as the current group view element and associated with the data column pointed to by pFKPart. If the current group view element is not associated with a primary key, it must represent a foreign key. Accordingly, at line 370, a new view element is created having a parent specified as the current group view element and associated with the data column pointed to by pFKPart. In either case, at line 390 a pointer to the newly created view element is added to the contents member variable of the current group view element. The routine then terminates. LISTING L20 illustrates an exemplary routine for setting the keyPair member variable of a view element. This routine is called by the AddForeignKeyO routine of LISTING L17. At line 60, the supplied group view element is consulted to determine a pointer to the view element it contains which is associated with the primary key column referenced by the foreign key column associated with the current view element. A suitable routine for performing this task is illustrated in LISTING L22. The routine then terminates. LISTING L21 illustrates an exemplary routine for setting the key pair member variable of a group view element. At line 60, the base class version of this routine (LISTING L20) is called on the current group view element. At a block defined by lines 90-120, the variable pVE is assigned as a pointer to each view element contained by the current group view element, in turn. At line 110, this routine is invoked on the view element pointed to by pVE. The routine then terminates. LISTING L22 illustrates an exemplary routine for returning a view element based on a particular column definition. At a block defined by lines 80-120, the variable pVE is assigned as a pointer to each view element contained in the current group view element, in turn. At line 100, a test is made to determine if the view element currently pointed to by pVE is associated with the data column supplied as the parameter. If so, the loop terminates. At line 130, the current value of the variable is pVE is returned, indicating the desired view element, and the routine terminates. LISTING L23 illustrates an exemplary routine for setting member variables to remember the existence of a relationship between the current group view element and the supplied group view element and the foreign key view element which carries the relationship. At hne 70, the related group view element is added to the member variable relatedTables (an unordered collection of pointers to related table group view elements). At line 80, the pointer to the foreign key view element is entered into the group view element's foreignKeys hash table, using the related group as the hash key. LISTING L24 is an exemplary routine for determining if a group view element contains a view element based on a given model object and returning it. At line 60, a variable "iter" is declared and initialized from the contents member of the current group view element. At line 70, a variable pVE is declared. In the loop bounded by lines 80-120, the variable pVE is set to point at each view element contained by the current group view element, in turn. At line 100, a test is made to determine if the current child group view element is based on the given model object. If so, the loop terminates. At line 130, the current value of the variable pVE is returned. If the loop bounded by lines 80-120 was terminated at line 110, the variable pVE will be non- NULL. In this case, the value returned by the routine at line 130 is a pointer to the desired child view element. Otherwise, the value returned will be NULL, indicating that no child view element was found. LIS TNGL25 is an exemplary routine for determining if a group view element contains another group view element that is based on a given model object and returning it. At hne 60, a variable "iter" is declared and initialized from the contents member of the current group view element. At line 70, a variable pVE is declared. In the loop bounded by Unes 80-120, the variable pVE is set to point at each view element contained by the current group view element, in turn. At Une 100, a test is made to determine if the current child view element is a group and if the current child group view element is based on the given model object. If so, the loop terminates. At line 130, the current value of the variable pVE is returned. If the loop bounded by lines 80-120 was terminated at line 110, the variable pVE will be non-NULL. In this case, the value returned at line 130 is a pointer to the desired child group view element. Otherwise, the value returned will be NULL, indicating that no child group view element was found. Form Run Time View Hierarchies LISTINGS L26-L30 are exemplary pseudocode routines for constructing view elements and group view elements that will be invoked by the routine described in LISTING L32. With reference to LISTING L26, the block defined by Unes 60-260 show initializers for data members of the view element class. In essence, each data member is initialized to one of the following: a constant value, a value suppUed by the base view object, a value supplied by the base view object's base model object, or a value supplied by the data column definition. At lines 280-300, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if it is a table, or to the containing group view element's parentTableGroup if it is not. At the block bounded by Unes 310-350, a test is made to determine if the parent table group is based on the same model component that the object being constructed (this object) is based on. If so, this view element must represent the data column for a multi-valued simple value component. The design tool does not allow NULL values for such columns, and thus the minimum cardinality for the current view element is set to one. The routine then terminates. LISTING 27 is a pseudocode constructor that will be invoked by the routine Ulustrated in LISTING L28. Specifically, the constructor initializes the data members Usted hi Unes 60-240 to constant values, to values obtained from the suppUed view object or its base model object, or from a table in the schema. At lines 260-280, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if the containing group view element is a table, or to the containing group view element's parent table group if it is not. The routine then terminates. LISTING L28 illustrates an exemplary pseudocode routine for initializing (constructing) a group view element that is associated with a table in the schema. Specifically, at line 60 the constructor of LISTING L27 is invoked to initialize the base view element class portion of the current group view element. The block bounded by Unes 70-150 initialize member variables of the group view element object to default or supplied values. At Une 170, a test is made to determine if the current group view element has no parent or if the view component that this view element is based on is a link. If so, at Une 190, the member variable "role" is set to indicate that the associated table was generated from a semantic object. At line 200, a test is made to determine if the current group view element has a parent. If the current group view element does have a parent, it must represent a Unk. In this case, the data members listed in lines 220- 270 are initialized with values obtained from the base model component or its base model component. A block defined by lines 300-450 is entered if the base model object of the base view object of the current group view element is a multi- valued group or simple valued component. In this case, at line 320 the role is set to indicate that. At Une 330, a test is made to determine if the base view object's base model object is a group. If so, the data members listed at Une 350-380 are initialized to values from the base view object or its model object. If the current group view element is based on a multi-valued simple value, the data members listed in lines 420-430 are initialized as shown. The routine then terminates. LISTING L29 illustrates an exemplary constructor invoked by the routine of LISTING L30 and takes into account single-valued groups. Specifically, the constructor initializes the data members listed in lines 50-220 to constant values, or to values obtained from the supplied view object or its base model object. At Unes 240- 260, the member variable parentTableGroup is initialized to point to the current view element's containing group view element if it is a table, or to the containing group view element's parent table group if it is not. The routine then terminates. LISTING L30 illustrates a pseudocode routine for initializing a single- valued group view element. Specifically, line 50 invokes the view element constructor of LISTING L29. Lines 60-140 list data members which are initialized to constant values or values obtained from the supplied view object or its base model component. At line 160, the member variable role is set to indicate that this group view element represents a single-valued group. The routine then terminates. LISTING L31 iUustrates an exemplary routine for creating a set of form run¬ time views associated with a particular object model. At Une 20, a parameter "theModel" is declared which references an object model for which run-time views are to be created. At Une 50, a variable "iter" is initiaUzed from the model as an iterator on the coUection of all object views in the model. Lines 60-70 declare variables used in the iteration. Line 80 declares and initializes a reference to the schema associated with the object model. During the block bounded by lines 90-140, the variable pView will be set to a pointer to each object view in the object model, in turn. At lines 110-120, a new group view element is created based on the object view pointed to by pView with a parent specified as NULL and associated with the table pointed to by the parameter returned from "theSchema.Lookup(pView-» BaseObjO)," which looks up the base semantic object of the object view in the schema and returns a pointer to a table object representing a database table generated from the given semantic object. At Une 130, the routine DefineRuntimeView is invoked with a pointer to the current view object and the schema as parameters. This routine is described next. LISTING L32 illustrates an exemplary routine for creating form run-time views in accordance with the invention. As is discussed above, form run-time views are created by combining information about an object model with the information contained in an object view hierarchy. Each form and each report will have an associated form run-time view. At line 20, a parameter called pViewObj is declared that points to a "current" view object in an object view hierarchy that has been constructed for a semantic object in an object model. When the routine is called for the first time, pViewObj will point to a root view object. Subsequent (recursive) calls wiU address view objects contained within the object view hierarchy. At Une 30, a parameter called "theSchema" is declared and will be used to provide information about the relational database schema generated for the current object model. Lines 60-100 define local variables "iter," pChild, pVE, pGVE, and pTable that the routine wiU use. The variable iter will be used to iterate across the contents of the current model object. During a loop bounded by lines 500-970, iter will return each child of the current model object, in turn. At line 110, a test is made to determine if the current group view element is associated with a table in the schema. If the current group element is associated with a table in the schema, a routine titled "AddPrimaryKey" is called at line 130 to add a view element representing the primary key of the table to the current group view element. At Une 140, a test is made to determine if the table associated with the current group view element is an intersection table. If so, the schema is consulted to determine a pointer that will point to a table generated from the current view object's referenced semantic object at line 160. At Une 170, a new group view element is created based on the current view object (pViewObj) having a parent specified as the current group view element (this) and associated with the table pointed to by pTable. At line 180, a pointer to the newly created group view element is added to the contents variable, which is a member variable of the current group view element. At line 190, a call is made to this routine on the newly created group view element with the current view object (pViewObj) and the schema of the object model as parameters. At line 200, a routine titled "AddForeignKey" is called to add a view element representing the foreign key between the intersection table and the semantic object table generated from the view object's base model object's referenced semantic object. At Une 210, a view element representing the foreign key between the intersection table and the intersection table's parent table group is added to the current group view element. At line 220, the routine terminates. At line 240, a test is made to determine if the current group view element is contained within another group view element. At line 260, a test is made to determine if the table associated with the current group view element was generated from a semantic object. If the current group view element is contained within another group view element and if the table associated with the current group view element was generated from a semantic object, at line 290 a local variable called pPairObj is declared as a pointer a model object and initialized to the current view object's base model object's pair object. At line 300, a variable called pSO is declared as a pointer to a model object and initialized to the current view object's base model object's referenced semantic object. At Une 310, a variable called pLinkParent is declared as a pointer to a group view element and is initialized to the current group view element. At 320, a test is made to determine if the current view object's base model object's referenced semantic object directly contains the current view object's base model object's pair object. If it does not, a function titled CreateParentGroup is called to create and return a pointer to a group view object based on the model object that does contain the current model object's pair, at line 340. An exemplary routine for performing this function is set forth in FIGURE L 15. At line 360, a test is made to determine if the table associated with the model object based on the container of the current view object's base model object's pair contains the foreign key that carries the relationship represented by the current view object's base model object and its pair. If so, the routine AddForeignKeyO is caUed to add the appropriate view elements to the group view element based on the container of the current view object's base model object's pair. At line 430, if the table upon which the current group view element is based is not a semantic object, a test is made to determine if it the carries the foreign key relating it to the current group view element's parent table group. If so, at Une 450 the routine AddForeignKeyO is called to add the appropriate view elements to the current group view element. The loop beginning at line 500 examines each of the children of the current view object, in turn. At line 520, a test is made to determine if the child of the current view object (current child object) is a link. If the current child object is a link, at Une 550 the schema is consulted to determine if a table has been generated for the current child object. At this point, if a table has been generated it will necessarily be an intersection table. Intersection tables are considered to be based on both link objects related to the table, i.e., the contents of the table will be reviewed from either side of the link. If an intersection table is not found, at line 570 the schema is consulted to obtain the table generated for the child's referenced semantic object. A new group view element is created at line 580 based on the current child object (pChild) having a parent specified as the current group view element (this) and associated with the table in the schema pointed to by pTable. At line 590, a pointer to the newly created group view element is added to the contents member of the current group view element. At line 600, a call is made to this routine on the newly created group view element with the current view object (pViewObj) and the schema of the object model as parameters. At Une 610, a test is made to determine if the table associated with the current group view element contains a foreign key representing the relationship between the current child's referenced semantic object and the table. If so, a routine titled AddForeignKeyO is called at line 620 to add the appropriate view elements to the current group view element. At Une 640, a test is made to determine if the current child object is multi¬ valued. If so, a new group view element is created at line 670 based on the current child object (pChild) whose parent is the current group view element (this) and associated with the table pointed to by the table returned by the schema from Lookup(pChild). At Une 690, the newly created group view element is added to the contents member variable of the current group view element. At line 700, a call is made to this routine on the newly created group view element with the current child view object (pChild) and the schema of the object model as parameters. At Une 720, a test is made to determine if the current child object is a group. In this case, it must be a single-valued group. If so, a test is made at line 750 to determine if a group view element already exists in the current group view element that is based on the current child object. If so, at line 770, a routine caUed ConfigureO is invoked on the preeexisting group view element to ensure that its member variables are set appropriately. A suitable routine for performing this task is shown in LISTING L34 and described in the accompanying text. If no group view element based on the current child object was found, a new group view element is created based on the current child object and having a parent that is specified as the current group view element, shown at line 810. At Une 820, a pointer to the newly created group view element is added to the contents member variable of the current group view element. A call then is made to this routine on the newly created or preexisting group view element with the current child view object (pChild) and the schema of the object model as parameters, as indicated at line 840. At Une 870, a test is made to determine if the current group view element already contains a view element based on the current child object. If so, at Une 890, a routine called ConfigureO is invoked on the preeexisting view element to ensure that its member variables are set appropriately. A suitable routine for performing this task is shown in LISTING L33 and described in the accompanying text. If no view element based on the current child object was found, at line 930 a new view element is created based on the current child view object having a parent specified as the current group view element and associated with the column in the table of its parent view element that is based on the model object on which the current child object is based, i.e., returned by Table0-»Lookup(pChild->BaseObj0). At line 950, the newly created view element is added to the contents member of the current group view element. Line 970 concludes the while loop that was started at line 500. Lines 980-1030 take into account view elements that represent data columns in the table generated by a multi-valued simple value model component. Specifically, at line 980 a test is made to determine if the current view object is neither a group nor a link, and if the current group view element is a table group. If all of these conditions are present, a new view element is created at line 1010 based on the current view object (pViewObj) and associated with the column in the table associated with the current group view element that is based on the model object on which the current view object is based, i.e., returned by Table0—»Lookup(pViewObj -. BaseObjO)- At Une 1020, a pointer to the newly created view element is added to the contents member variable of the current group view element. The routine then terminates. LISTING L33 illustrates an exemplary routine for performing initialization steps that are necessary for view elements in a form run-time view, and not performed when view elements are constructed solely from model components. Constructing view elements solely from model components occurs during the creation of a form run-time view when AddPrimaryKeyO is called for a table defined as using a model object as the primary key (i.e., having a 'data key'). At line 60, the variable viewObjID is set to the object ID of the specified view object. At line 70, the allowed action for the current view element is set based on the allowed action specified by the supplied view object. The routine then terminates. LISTING L34 illustrates an exemplary routine for performing initialization steps that are necessary for group view elements in a form run-time view, and not performed when group view elements are constructed solely from model components. At line 60, the base class version of this routine is caUed with pViewObj as a parameter (LISTING L33). At lines 70 and 80, the DeleteAllowed and NewAllowed flags are set, respectively, as specified by the base view object. The routine then terminates. LISTING L35 is an exemplary routine for determining if a group view element contains a view element based on a given view object and returning it. At line 60, a variable "iter" is declared and initialized from the contents member of the current group view element. At line 70, a variable pVE is declared. In the loop bounded by Unes 80-130, the variable pVE is set to point at each view element contained by the current group view element, in turn. At lines 100-110, a test is made to determine if the current child group view element is based on the given model object or on the given view object's base model object. If so, the loop terminates. At hne 140, the current value of the variable pVE is returned. If the loop bounded by lines 80-130 was terminated at Une 120, the variable pVE will be non-NULL. In this case, the value returned by the routine at hne 140 is a pointer to the desired child view element. Otherwise, the value returned will be NULL, indicating that no child view element was found. LISTING L36 is an exemplary routine for determining if a group view element contains another group view element that is based on a given model object and returning it. At Une 60, a variable "iter" is declared and initialized from the contents member of the current group view element. At line 70, a variable pVE is declared. In the loop bounded by Unes 80-160, the variable pVE is set to point at each view element contained by the current group view element, in turn. At lines 100-120, a test is made to determine if the current child view element is a group and if the current child group view element is based on the given view object or its base model object. If so, the loop terminates. At line 170, the current value of the variable pVE is returned. If the loop bounded by lines 80-160 was terminated at line 140, the variable pVE will be non-NULL. In this case, the value returned at line 170 is a pointer to the desired child group view element. Otherwise, the value returned wiU be NULL, indicating that no child group view element was found. Run Time View Operations FIGURE 23 illustrates an exemplary user interface in the form of a state diagram for storing and retrieving data to and from a relational database using the custom apphcation 51. As will be appreciated by those familiar with database systems, there are four operations fundamental operations that can be performed on a database. These include: inserting a record, deleting a record, updating a record, and query operations, i.e., asking the database to return one or more records that match a search. In the upper left-hand corner of FIGURE 23, a user may begin by selecting a form that has been created by the design tool for a semantic object in the object model, as indicated by reference numeral 910. As an alternative, the user may invoke an appropriate command to exit the routine, and hence the custom application, as indicated by reference numeral 912. If a form is selected, it will be displayed with blanks in each of the form's fields, as indicated at state 914. At this point, a user may enter data and the data will be displayed on the form (event 916); invoke an insert command (event 918), clear the form (event 920); or exit the routine (event 922). If an insert command is entered while at state 914, an insert routine is called by the custom apphcation, as shown at state 924. A suitable routine for inserting a record into the database using a run-time view is set forth in LISTING L41, and described in the accompanying text. Upon return from the insert routine, the custom application will display an error message if the insert failed, shown at state 926, and return to state 914, where the form and data, if any, that has previously been entered is displayed. If the insert succeeded, the data is written to the database and the form is cleared and redisplayed, as indicated by state 928. This state will also be reached if the user invokes a "clear form" command at state 914. The custom application remains at state 914 until a command is entered by the user. If a query command is entered while at state 914, a query routine is called by the custom appUcation to perform the database search, as shown at state 924. A suitable routine for querying data from the database using a run-time view is illustrated in LISTING 46, and described in the accompanying text. Depending upon the results of the query, the query routine will return one of three parameters that are used by the custom appUcation to display the appropriate information to the user. First, if no records were located in the query, the custom application will display a message to the user indicating this, as shown at state 932, and will then return to state 914, where the form and query information are redisplayed. Second, if a single record is found, this record will displayed in the form, as indicated at state 934. FinaUy, if multiple records are found, the custom application will display a listing of aU the records, as indicated at state 935. In the case where multiple records are found, the user has the option of selecting a record from the list. Assuming a record is selected, the selected record will be displayed in the form, as indicated at state 934. At this point, the user may perform the foUowing operations: (1) change the contents of the record by entering data (event 936); (2) clear the form without affecting the stored record, wherein the custom application will clear the form at state 928, and then display a blank form, at state 914; (3) update the record by entering text and then invoking an "update" command (event 940); (4) delete the record (event 942); or (5) exit the custom appUcation (event 944). If an update command is entered while at state 934, an update routine is called by the custom application, as shown at state 946. A suitable routine for updating a record in the database using a run-time view is shown in LISTING L37, and described in the accompanying text. If, after calling the routine, the update was successful, the custom appUcation returns to state 928 where the form is cleared, and then to state 914 where the blank form is displayed. If the update did not succeed, i.e., data inappropriate for that record was entered, an error message is displayed to the user, as indicated at state 948. Once the user acknowledges the message, the custom appUcation returns to state 934, where the record, along with the update information, is redisplayed in the form. If a delete command is entered while at state 934, the custom application will caU a delete routine to remove the record from the database, as shown at state 942. A suitable routine for a deleting record from the database is shown in LISTING L43, and described in the accompanying text. If the delete was successful, the form is cleared by the custom appUcation at sate 928, and the blank form displayed to the user, at state 914. Otherwise, the delete has failed, and an appropriate message is displayed to the user, as indicated at state 950. A delete record command would fail, for example, if this was the last record for a semantic object or model component that has a minimum cardinality of one. Once the user acknowledges the message, the custom application returns to state 934, where the record is redisplayed in the form. The insert, update, query and delete routines will now be described. An Overview of Semantic Object Modeling vis-a-vis Relational Database Tables In any system providing access to data in a database, the fundamental functions are the entry and retrieval of data. Entry of data involves the specification of values to be entered into the database, i.e., column values, as weU as where to put the data, i.e., a table specification and a row specification within that table. Data retrieval involves the selection of a row or rows to examine (and possibly update), the display of candidate rows to associate with a row in some table via foreign keys, and the display of data already so associated. When working with semantic objects, tables are used in several ways. A table generated from the base portion of a semantic object ("an SO table") defines "semantic object instances," one for each row. Each semantic object instance represents a single thing in the mind of a user or data modeler who defined the object model. In the object model set forth in FIGURE 8, each row in the table generated from semantic object "order" represents a different order instance. This fits well with common experience, where an order is often represented by a single form. Multi-valued components within a semantic object may also generate a table; multi-valued object link components are the exception to this rule, as described below. For example, in the order semantic object the model component "Une item" is a multi-valued group, and will cause a table to be created to hold data for line items in an order. Tables generated for multi-valued data components are different from SO tables, in that the rows in these tables do not define semantic object instances. Instead, they contain data which cannot be represented in the single row of the SO table, but which are (logically) just as dependent on the existence of such a row as the columns in the SO table. Object link components are treated differently because they do not represent data values in the database or the object model. Instead, they represent relationships between semantic objects. These relationships are carried in the usual way (by foreign keys), and since semantic objects always generate a table, object links do not cause another table to be generated if the relationship is one to one or one to many. In these cases, the relationship can be represented by placing the foreign key columns in one of the SO tables. If, however, the relationship is many to many, an intersection table is generated with rows defined as containing pairs of foreign keys, one for each of the related SO tables. Each row in an intersection table is dependent on both of the related object instances; if either instance related to a given intersection table row is deleted or the relationship it represents is disconnected, the intersection table row must be deleted. Inherent in semantic object modeling is a method of restricting the amount of freedom one has in using a relational database. The structure added by these restrictions allows the definition of a small set of query operations to cover aU semantically valid cases. The types of queries include: 1) queries defining a set of semantic object instances to be examined using a given object view hierarchy, i.e., for report printing or for display in a form; 2) finding the set of rows in a table related to a particular object instance, e.g., the line items for an order, or information about the customer related to a particular order; 3) queries defining a set of semantic object instances available for connection on a particular relationship. This is different from a type 1 query in that if an object instance is already related to as many other object instances as the maximum cardinality for that relationship, the object will not be returned by a type 3 query. When working with query results, database systems must provide a mechanism for determining the number of result rows and moving among them, and run-time views are no exception. In place of database cursors, the group view elements provide operations for defining and executing queries of all three types defined above, and working with the resulting sets of rows. These operations are equivalent to those provided by conventional cursors, with the addition of semantic object based querying (type 2 and 3 queries - type 1 queries are similar to traditional queries). View elements can provide access to two different result sets of rows at once, one called a "query result set," which may not be updated, and one editable set, caUed the "current" set, which may contain updated or new values, including entire new rows. It is possible to move a row from the query result set to the current set. This is required, for example, if a user desires to make changes to data which has been saved in the database. Positioning in a result set is handled by means of requests to group view elements. View elements and group view elements with parent group view elements take the current position of the parent group view element into account when returning values or current positions. Dependent multi-valued group view elements must, in general, maintain the effect of separate cursors for each parent table row position. Movement in the current result set is defined for all table group view elements; that is group view element's created in association with a database table, i.e., having a role of SO TABLE (a semantic object table), ATTR TABLE (a component table), or X TABLE (an intersection table) in the routines discussed below. Movement in the query result set (and type 1 & 3 queries) is defined for group view elements with a role of SOJTABLE or X TABLE. For programming convenience, many operations on X TABLE group view elements are just forwarded to the SOJTABLE contained by the X TABLE. Type 2 queries return their results sets as current results, as opposed to query results. The cursor operations that may be performed for a group view element include: FirstO — moves to first row in set, does a FindO if needed NextO — moves to next row in set PreviousO — moves to previous row in set LastO — moves to last row in set CountO ~ returns count of rows in set, does a FindO if needed GetCurrentPosO — returns a token representing the current row position in the set SetCurrentPosO — makes the row indicated by the supplies token the current row QueryO ~ type 1 & 3 queries (LISTING L46) FindO ~ type 2 query (LISTING L47) NewRowO — adds a new (all NULL) row to the current set, makes it the current row View elements provide access to database column values corresponding to the result sets, and additionally, can provide the original value in the current result set if the column represented by the view element has been updated on the row specified by the parentTableGroup. Referential Integrity and Database Transactions Semantic object models generate databases in domain-key normal form, and the procedures given herein maintain the referential integrity of the database without any DBMS support. If the DBMS implements declarative referential integrity constraints, it may be necessary to group several group view element operations into one DBMS transaction. If the DBMS enforces constraints on per-statement basis within a single transaction, it may be necessary to order the statements within a transaction appropriately. Relationships which are mandatory from both sides are a particular case of this; these arise not only from one-to-one object Unks which are required on both sides, but also from required multi-valued group or simple value components. In the 1.1:1.1 case, databases which enforce referential integrity on a per-statement basis are not given complete information about the nature of the relationship if any records are to be inserted. This is also true of databases which do not provide the "CREATE SCHEMA" syntax defined in recent SQL standards; this includes most commercial DBMS's. In the required multi-value component case, the primary conflict is between the natural order of operations on the DBMS and the view elements. The DBMS wants to have the SO table row inserted first, but the VaUdateCountsAndCardsO function will return an error if the required dependent multi-valued group view element has no rows. Alternative implementations of the DoDatabaseAO functions which create SQL statements as strings and execute them as a single batch (after suitable reordering) will be obvious to those skilled in the art. Surrogate keys Surrogate keys are assumed to be supplied by the run-time view programmer, immediately after making a call to NewRowO, thereby adding a row to the 'current' result set and positioning the group view element (GVE) to the new row. If this step is delayed for any reason, suitable modifications to ConnectO will be needed to track the need to fiU in appropriate values for the foreign keys before (or as) the row containing the foreign key is added to or updated in the database. Locking The exemplary routines DoDatabaseUpdate() and DoDatabaseDeleteO show a common form of optimistic locking which checks that none of the data columns read by the current group view element have been changed by another user. Large string, e.g., memo, and binary objects are excluded from this check procedure. If the database can only be accessed by a single user, or records are locked when read from the DBMS, simpler predicates can be used which only reference the primary key of the row to be updated or deleted. The changes needed to do this are obvious. Exemplary Routines for Performing Run Time View Operations LISTING L37 Ulustrates an exemplary routine for saving updated values entered into view elements contained by a table group view element. The table group view element must be bound to data read from the database before any contained view elements are updated. This routine is called on the table group view element. At line 50, a test is made to determine if the current group view element allows only read access. If so, an appropriate error is returned. At line 100, a test is made to determine if the current group view element is associated with an intersection table. If so, as a convenience for the programmer writing code which calls this routine, this routine is invoked on the child group view element which is associated with the table generated by the referenced semantic object of the object Unk on which the current group view element is based (i.e., the call is forwarded to the child table group view element). This is correct because intersection table rows are only added and deleted by the ConnectO (LISTING L39) and DisconnectO (LISTING L40), and are never updated. Forwarding the call allows the programmer to treat updates to any multi-valued object Unk uniformly, without regard for the maximum cardinality of the object link's pair. Otherwise, at line 170, the function ValidateCountsAndCards (LISTING L42) is called. At line 180, a test is made to determine if an error was returned. If an error was not returned, at line 200 the function DoDatabaseUpdate is called to generate and execute appropriate SQL statements to perform the update. A suitable routine for performing this task is illustrated in LISTING L66, and described in the accompanying text. At Une 230, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L38 illustrates an exemplary routine for determining the group view element contained by an intersection table associated with a semantic object table. The loop bounded by the lines 70-110 assigns the variable pFK as a pointer to each foreign key carrying a relationship between this group view element and another group view element (the iterator fklter returns only the values in the foreignKeys hash table; it does not return the keys themselves). At line 90, a test is made to determine if the current group view element is the table group which contains the table group associated with the key pair of the current foreign key (the grandparent table of the current foreign key's key pair). If so, the variable pGVE is set to the current foreign key's key pair's parent table group, shown at line 100. This will cause the loop to terminate. At line 120, a pointer to the desired group view element is returned, and the routine terminates. LISTING L39 illustrates an exemplary routine for establishing a relationship between two semantic object instances. In particular, this routine connects the current instance of a group view element to its parent table group. More specifically, the current instance is defined as an instance that is in the current buffers, i.e., a newly created instance or an instance that was returned from a query. If the current instance is defined from a group of instances returned from a query, the routine will be invoked on the instance that is currently highlighted. The parameter fUseQuery determines whether the connection is from a current instance stemming from the data located in the current buffers or from a query, and is declared at Une 30. At Une 60, a variable pFK is declared and assigned a pointer to the foreign key relating the current group view element to its parent table group. At Une 70, a test is made to determine if the current group view element represents an intersection table. If so, a test is made to determine if the request is to connect to a queried result, as indicated at Une 90. If the current request is not specified as connecting to a query, a suitable error is returned at line 100. This is because intersection tables are not represented in the object model, and therefore are not represented on forms as such. In other words, a user cannot connect to a new row of an intersection table because there is no user specified data in an intersection table row. At Une 110, a function entitled NewRow is called to create a new row in the current data buffer and make it the current row of this group view element. A routine for doing this is not set forth herein, but will be apparent to those skilled in the art. At Une 120, a routine entitled CopyKey is called on the foreign key view element to cause it to copy the primary key value of the parent table group to the current row. At Une 130, this routine is invoked on the intersection table child semantic object table group view element. This will cause the foreign key connecting this group view element to be placed in the child semantic object table group view element. At Une 140, a routine entitled DoDatabaselnsert is called to add the current row to the database. A suitable routine for performing this task is described in LISTING L71, and described in the accompanying text. If the current group view element does not represent an intersection table, the block defined by lines 160-290 is executed. Specifically, at line 180, a test is made to determine that the specified object instance is available for connection. A connection is available if the foreign key view elements are NULL. If not, an appropriate error is returned at Une 210 indicating to the programmer that an error has occurred. At line 230, a test is made to determine if a connection is to the current instance of the query result set of the current group view element. If so, at line 250, a new row is allocated by calling an appropriate routine. At Une 260, the current instance of the query result set is copied to this new row. At line 280, a routine entitled CopyKey is called on the foreign key view element, causing it to set its value from the value of its key pair, i.e., the appropriate primary key value(s). At Une 300, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L40 Illustrates an exemplary routine for removing a relationship between two semantic object instances. In particular, this routine disconnects the current instance of a group view element from its parent table group's current instance. For example, if a user wishes to delete an order that is associated with a particular customer, the Disconnect routine will be called to break that association. In deleting the order on an order form, the routine would be invoked on the customer group view element. Connections (associations) between semantic objects can also be broken as a result of a user command to clear (disconnect) the link, or as a preliminary step in changing connected instances (e.g., if an order instance was connected to the wrong customer instance, the existing link must be cleared before a new connection is made). At lines 70-80, a test is made to determine if the object link pair of the model object upon which the current group view element is based has a non-zero minimum cardinality. If so, an error wiU be returned at line 100 if the minimum cardinaUty is one, or if removing the connection to this instance will violate the specified minimum cardinaUty of the object Unk pair. For example, if a customer must have at least one order, and this deletion would eUminate the customer's last order, a suitable error will be returned. At line 120, a test is made to determine if the current group view element represents an intersection table. If the current group view element does represent an intersection table, the table will contain only foreign key columns, all of which are to be set to NULL as a result of this operation. As will be appreciated by those skiUed in the art, this would result in a blank row, which is undesirable. Thus, the entire row is deleted, as shown at Hne 160. If the current group view element does not represent an intersection table, a pointer to the view element representing the foreign key connecting the two tables is obtained by using the parent table group as a hash key in the "foreignKeys" hash table and assigning the result to the variable pFK. This is shown at Une 200. At Une 210, view elements representing the foreign key are set to NULL, thereby breaking the relationship. At line 230, an indication of the success or failure of this routine is returned. This operation is not final until sent down to the database using the update routine shown in LISTING L37. LISTING L41 iUustrates an exemplary routine for inserting a row into a relational database table corresponding to an instance of a semantic object or a multi- valued group in the object model. At Une 60, a test is made to determine if the current group view element represents an intersection table. As was discussed above, rows in an intersection table represent a many-to-many relationship between two semantic objects and are created and deleted using the routines Connect and Disconnect, respectively, shown in LISTINGS L39 and L40, and discussed above. At line 70, if the current group view element is an intersection table, an error is returned to indicate to the caUing routine that a programming error has occurred. At Une 80, a test is made to determine if the insertion meets the requirements of the object model, e.g., the associated view element is "minimally complete." A view element is minimally complete if it contains view elements for aU the required simple value components and links in the group component or semantic object upon which it is ultimately based. For example, assume an order must have a customer. If a user is reviewing an order form which does not contain view elements for a customer, it is not possible to create an order instance from that form. An associated customer is required. Other examples in which permission to insert is denied include: where the "add permission" has been set to false in a form, or where the current form is opened using an open form action where "allow new" has been set to false. At line 110, a routine called ValidateCountsAndCards is called to validate the count of the current group view element and the cardinalities of all the view elements it contains. AN exemplary routine for performing this task is illustrated in LISTING L42. At Une 120, a test is made to determine if an error indication has been returned by the ValidateCountsAndCards routine. If not, a test is made at line 140 to determine if the current group view element has a parent and does not represent a Unk, i.e., it is not a semantic object table. In essence, this check will look to see if the current group view element is based on a multi-valued group or simple value component. If these conditions are met, a routine is invoked to connect this group view element's instance with its parent table group. A suitable routine for performing this task is the Connect routine in LISTING L39. At line 180, a test is made to determine if an error has occurred. If no error has occurred, a routine entitled DoDatabaselnsert is called at line 190. A suitable routine for performing this task is set forth in FIGURE L32, and described in the accompanying text. At line 210, an indication of the success or failure of the routine is returned to the caUer. LISTING L42 illustrates an exemplary routine for vaUdating the count of a current group view element and the cardinalities of all the view elements it contains. By way of an overview, this routine will look to the contents of the current group view element to see if the cardinality of each view element is satisfied (Unes 90-490) and that the counting constraints on the current group are satisfied (Unes 500-630). More specifically, at Unes 40-70 local variables "err," "iter," "pVE," and "nonNuUCount" are declared. At Une 90, a while loop begins in which the view elements contained by the current group view element are returned by iter and assigned to the variable pVE. At Une 110, a test is made to determine if the current child view element is multi-valued, i.e., has a maximum cardinality greater than one. If so, a local variable count is declared and initialized to the number of rows in the set associated with the current child view element, as indicated at line 130. At Une 140, a test is made to determine if this count is greater than the maximum cardinality for the current group view element. If the maximum cardinality has been exceeded, an error indication is set at Une 160 to indicate to the calling routine, and ultimately to the user, that the maximum cardinality has been exceeded. At line 190, a test is made to determine if the count is less than the minimum cardinaUty for the current child view element. If so, an error indication is set at line 210 to indicate to the calling routine, and ultimately to the user, that the minimum cardinality requirements have not been met. At line 240, a test is made to determine if the count is non-zero. If so, one is added to the number of non-NULL view elements contained in the current group view element. To reach Une 270, the current child view element must be single-valued. At Une 290, a test is made to determine if the child view element is NULL. At line 310, a test is made to determine if the current chUd view element has a minimum cardinality greater than zero. If both conditions are met, an error is set at Hne 330 to indicate to the calling routine, and ultimately to the user, that a required item is missing from the current group view element. At Une 390, a test is made to determine if the current chUd view element is associated with an object in the object model. If so, at line 400 one is added to the number of non-NULL view elements contained in the current group view element. At line 410, a test is made to determine if the current child view element is a single- valued group view element. If so, this routine is called on the current child view element. If, at line 500, no error has occurred, a test is made to determine if the non- NULL count is not equal to the maximum count (shown at Une 520). If the non- NULL count is equal to the maximum count, there is no error, and the routine returns. Otherwise, a test is made at line 540 to determine if the non-NULL count is greater than the maximum count. If so, an error indication is recorded to this effect at line 480. At Une 580, a test is made to determine if the non-NULL count is less than the minimum count. If it is, an error indication to this effect is recorded at line 600. At Une 640, an indication of the success or failure of this routine is returned. LISTING L43 iUustrates an exemplary routine for deleting a row from a relational database table corresponding to an instance of a semantic object or a multi- valued group in the object model. At line 40, the variable "err" is initialized to SUCCESS, which is defined as zero. At Une 50, a test is made to determine if the current group view element is not an intersection table. If it is not an intersection table, the variable iter is declared and initialized to a collection of group view elements called relatedTables. The variable relatedTables is a member variable of the current group view element and defines group view elements that have a direct relationship with the table on which the current group view element is based, i.e., the table on which the current group view element is based has a foreign key to a related table, or the related table has a foreign key of the table on which the current group view element is based. At Une 80, a local variable pGVE is declared. The while loop defined by Unes 90-210 will iterate across the related tables of the current group view element setting pGVE as a pointer to each table. SpecificaUy, at line 110 a test is made to determine if the current related group view element is a Unk. If so, a routine titled DisconnectAll is called on the related group view element to disconnect aU of the instances represented by it from the current row of the current table. A suitable routine for performing this task is illustrated in LISTING L44. As an example, when an order is deleted, it needs to disconnect from its associated customer. Otherwise, at line 150, a test is made to determine if the current related group view element is the current group view element's parent table group. If not, a routine entitled DeleteAU is called on the current related group view element to delete all related instances of the current group view element, as indicated at Une 170. As an example, when an order is deleted, all the Hne items related to that order must also be deleted. An exemplary routine for performing this task is set forth in LISTING L45, and described in the accompanying text. At Une 190, a test is made to determine if an error has occurred. If so, the while loop is terminated. This concludes the loop defined by lines 90-210. At Hne 230, a test is made to determine that no error has yet occurred. If an error has not yet occurred, a routine entitled DoDatabaseDelete is called at Une 240 to delete the current row in the database corresponding to the current instance of this group view element. At Une 250, an indication of the success or failure of this routine is returned. LISTINGL44 illustrates a suitable routine for disconnecting instances of a semantic object related to the current table. At line 50, the variable "err" is set to the result of a function call to "First," which positions the cursor represented by the current group view element to the first row in its set. The loop bounded by lines 60-110 will continue until the variable err becomes non-zero. Specifically, at Une 80, a routine entitled Disconnect is called to disconnect the current instance of this group view element from its parent table group. At line 90, a test is made to determine if the disconnect was successful. If so, the variable err is set to the result of moving the cursor represented by the current group view element to the next row. This concludes the loop bounded by Unes 60-110. At Une 120, a test is made to determine if the current value of err indicates that aU the rows in the cursor represented by the current group view element have been examined. In the test is positive, either there were no rows or aU the rows were successfully disconnected. Thus, at Une 140 the variable err is set to indicate this routine was successful. At line 160, an indication of the success or failure of this routine is returned. LISTING L45 is an exemplary routine for deleting all the object instances in the set represented by a group view element. At line 50, the variable "err" is set to the result of a function call to "First," which positions the cursor represented by the current group view element to the first row in its set. The loop bounded by lines 60-110 will continue until the variable err becomes non-zero. SpecificaUy, at line 80 a f nction entitled Delete is called to delete the current row in the table represented by the current group view element. At Une 90, a test is made to determine if the deletion was successful. If so, the variable err is set to the result of moving the cursor represented by the current group view element to the next row. At Hne 120, a test is made to determine if the current value of err indicates that aU the rows in the cursor represented by the current group view element have been examined. In the test is positive, either there were no rows or aU the rows were successfully deleted. Thus, at line 140 the variable err is set to indicate this routine was successful. At Hne 160, an indication of the success or failure of this routine is returned. LISTING L46 iUustrates an exemplary routine for performing a query on a relational database using a group view element. Intrinsic to this discussion of the following routines, it is noted that every view element may have a predicate string associated with it. This permits a user of the query routine to construct a database predicate without direct reference to database column or table names. At line 160, a parameter entitled newPredicate is declared, which will replace the current predicate on the current group view element, if the new predicate is not NULL. At Une 170, a parameter entitled fUseConnectPower is declared, which if true (non-zero) indicates a type 1 query is desired, and if false (zero) a type 3 query is desired. Query types 1-3 were described above in pages 78-79 of the detailed description. At line 220, a test is made to determine if the current group view element represents an intersection table. If so, this routine is invoked on the child semantic object table of this intersection table, as indicated at line 240. At line 250, an indication of the success or failure of the call invoked at line 240 is returned. Otherwise, at line 270, a test is made to determine if a new predicate was supplied. If so, the predicate value of the current group view element is replaced with the new predicate, at line 280. At Une 310, a routine entitled Select is invoked to generate and execute an appropriate SQL query. A suitable routine for performing this task is set forth in LISTING L48, and described in the accompanying text. At line 320, an indication of the success or failure of the routine is returned. This routine then terminates. LISTING L47 illustrates an exemplary routine for selecting all of the data represented by the current group view element that is related to the current instance of this group view element's parent group view element. At line 160, a test is made to determine if the current group view element is single-valued. If so, a suitable error is returned. This is done because in the implementation described tables which have a single-valued relationship to their parent table group are read at the same time as the parent table group. This restriction is possible because the routine Select is always caUed with the extended read indicator set to true. At line 180, a test is made to determine if the current group view element has a parent table group. If it does not, it is a top-level group view element and only type 1 queries should be invoked. Thus, a suitable error is returned to the programmer to this effect at line 200. At line 230, the Select routine (described next) is invoked to perform the requested operation. At line 240, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L48 is an exemplary routine for constructing and executing an SQL string to perform a query. At the block defined by lines 100-240, a predicate is built for the select statement being generated. As a predicate is being built, a hierarchy of table references (rooted at tableRef) that describes the tables involved in the Select and the join conditions between them is constructed At Une 280, a function entitled Gather Join is invoked on the root of the TableRef hierarchy, which generates strings containing all of the column names and table names required, as well as the join portion of the predicate to be used. The remainder of the function constructs a SQL string and executes it. Reviewing the LISTING L48 in greater detail, at line 90, a root TableRef object is declared referencing the current group view element, since the table associated with the current group view element wiU always be involved in the generated select. At line 110, a test is made to determine if the parent constraint flag is specified as true, i.e., this is a type 2 query. If it is, at Une 130 a routine entitled ParentlnstancePredicate is caUed to generate an appropriate predicate string. A suitable routine for performing this task is illustrated in LISTING L49, and described in the accompanying text. Otherwise, at Une 170 a test is made to determine if the connect power flag is specified as true, i.e., this is a type 3 query. If so, at Une 200 a function entitled ConnectPowerPredicate is called to construct a suitable predicate string. A suitable routine for performing this task is illustrated in LISTING L52, and described in the accompanying text. At line 240, a routine entitled DefinePredicateDown is called to traverse the run-time view hierarchy and compose an appropriate predicate string from any predicate strings found in group view elements directly or indirectly contained in the current group view element. This is done for all types of queries. At line 280, the Gather Join is called, as previously described. At the block defined by lines 300-320, a SQL command string is constructed from the strings generated above. At line 340, a function entitled ExecuteSQLString is called to execute the select on the database. While not shown expUcitly, this routine is intended to suggest one of the many ways of executing a SQL string generated by an appUcation program. Similarly, the binding and retrieval of the returned data is not shown, but will be apparent to those skilled in the art. At Une 350, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L49 Illustrates an exemplary routine for defining a predicate string specifying rows of a table associated with a group view element which are related to the parent table group of the group view element by the relationship specified by the current group view element. At Une 80, a variable pFK is declared and initialized as a pointer to a view element representing the foreign key carrying the relationship between the current group view element and its parent table group. At Une 90, a variable pFKTableGroup is declared and initialized as a pointer to the group view element associated with a table which contains the foreign key. At Une 120, a test is made to determine if the foreign key resides in the table associated with the current group view element. If so, a function entitled ParamJoin is invoked on the foreign key view element. This routine, set forth in LISTINGS L50 andL51, generates strings which compare a foreign key column to a primary key value or a primary key column to a foreign key value, depending upon its second parameter. The result is returned in the variable ParentPredicate. If the foreign key does not reside in a table associated with the current group view element, a test is made to determine if it resides in an intersection table, as indicated at line 200. At line 270, the variable pFK is assigned as a pointer to the foreign key that relates the intersection table to its parent table group. At Hne 280, the routine ParamJoin is invoked on the foreign key to produce a predicate which relates rows of the intersection table to the table associated with its parent table group. At line 300, a routine entitled SubQueryStr, described in LISTING L54, is invoked to generate a sub-query specifying appropriate rows of the intersection table. At Une 310, the variable parentPredicate is assigned a string defining a predicate which evaluates to true only for those rows of the table associated with the current group view element which are shown in the intersection table as being linked to a current instance of the intersection group view element's parent table group. The block defined by lines 340-410 will be entered if the foreign key resides in the table associated with the current group view element's parent table group, and that parent table group is not an intersection table. In this case, at line 400 the routine ParamJoin will be invoked on the foreign key view element to define a suitable predicate. The block defined by lines 440-620 will be entered if the foreign key is neither in the table associated with the current group view element nor the table associated with the parent table group. This block constructs a predicate string which evaluates to true for any row of the table associated with the current group view element which is related to one or more rows in the child table which contains the foreign key relating this group view element to its parent table group. If the group view element containing the foreign key is not a direct child of the current group view element, this process is repeated for any intervening table groups. At line 640, the generated predicate string is copied to the predicates parameter, and is thereby returned to the calHng routine. The routine then terminates. LISTING L50 illustrates an exemplary routine for generating a join relating a primary key column to a foreign key value, or vice versa. This routine is defined on a group view element and invokes itself on each of its contained view elements, thereby causing a concatenated equijoin predicate to be generated. With reference to LISTING 51, Unes 120-210 determine which of the current view element and its key pair is to supply the value and which is to supply the column name in the database to be examined. Lines 230 and 240 build a string specifying the comparison. At Une 250, the generated string is appended to the predicate being accumulated. If the predicate was not empty, the generated string will be connected to the predicate using "AND". LISTING L52 illustrates an exemplary routine for generating a predicate selecting rows in a semantic object table satisfying the connection power specified for this group view element. Specifically, if the connection power is specified as AVAILABLE, a predicate clause will be generated which evaluates to true for all rows of the semantic object table associated with this group view element that are connected to fewer instances of the semantic object containing the object Hnk upon which the current group view element is based than the maximum cardinality of the pair of the object Unk upon which the current group view element is based. If the connect power of the current group view element is specified as FREE, a predicate clause will be generated which selects all rows of the semantic object table associated with this group view element that are not connected to any instances on the relationship specified by the pair of the object upon which the current group view element is based. If the connect power of the current group view element is specified as NONE, then a predicate which is always false is generated. The generated predicate is returned at Une 730. The routine then terminates. LISTING L53 illustrates an exemplary routine for defining a subquery which evaluates to true if there are any rows satisfying the predicates specified on the current group view element or any view element it contains, directly or indirectly. If there are no such predicates, no subquery is defined. The various functions for accomplishing this task are described next. LISTING L54 illustrates an exemplary routine for generating a select statement from the supplied values and using the given TableRef object to generate a Ust of tables to select from, along with appropriate join conditions. LISTING L55 illustrates an exemplary routine for gathering together predicates on the current group view element and view elements contained within it. Predicates on contained view elements fall within three broad categories. The first are predicates on simple view elements directly contained within the current group view element. These predicates are prefixed with the table and column name of the given child view element and joined to the predicate string being generated using AND, if necessary. Second, group view elements not representing tables add any predicates they contain to the current predicate string by a call to this routine on the group view element. The third category is group view elements representing tables. These may be directly or indirectly related and may be single-valued or multi-valued. If they are indirectly related, i.e., the foreign key carrying the relationship is not directly contained within the current table group view element or the child group view element, then a routine entitled DefinePredicateUp (LISTING L57) is invoked to construct an appropriate predicate string. If the relationship is direct and multi¬ valued, then the routine SubQueryPredicate is invoked on the related group view element to generate an appropriate predicate string. If the relationship is direct and single valued, the routine JoinPredicate is invoked on the child group view element. This routine is set forth in LISTING L56, and described next. The routine DefinePredicateDown returns three distinct values. The first is the number of predicates found on this branch of the view element hierarchy; the second is the generated predicate string; and the third is returned in the form of modifications to the TableRef object passed as a parameter. LISTING L56 iUustrates an exemplary routine JoinPredicate. This routine encapsulates a caU to DefinePredicateDown and converts any joins implied by the specified predicates to inner joins. This conversion is both possible and necessary because any rows in the table associated with the current group view element that are selected by a generated predicate must necessarily have a connection to the rows of the table which cause them to be selected. LISTING L57 illustrates a routine entitled DefinePredicateUp that is similar to the routine DefinePredicate Down of LISTING L55 in that it gathers predicates within a run-time view hierarchy. However, DefinePredicateUp will traverse a hierarchy from a foreign key up (via parent view elements, rather than through child view elements, including across table group view elements) until a semantic object table group element is reached. This semantic object table group will be related to its parent by the foreign key that initiated the sequence of calls to the routine. The specific Unes of code illustrated in the pseudocode routine will be apparent to those skilled in the art. LISTING L58 illustrates a class definition for the class TableRef. The TableRef class is used to define a hierarchy of table group elements and join conditions. Each TableRef object is associated with a group view element pointed to by its pGroupView member variable, as indicated at Une 310. The type of the join is indicated by the joinType member variable, which takes on values from the enumeration listed in Unes 40-70. The member variables pParent and tableRefList, define the hierarchy by carrying the parent and child relationships respectively, as indicated at Unes 330 and 340. The non-trivial member functions are set forth in LISTINGS L59-L65, and discussed below. LISTING L59 LUustrates a constructor for the TableRef object. At Une 70, a test is made to determine if this is the root of the TableRef tree or is associated with a group view element which is required in its parent context, i.e., its minimum cardinality is non-zero. In this case, the joinType is set to INNER. Otherwise, the joinType is set to indicate that a left outer join should be used. At line 110, if a ParentTableRef object was specified, its Attach() function is called to add the current object to the parent's tableRefList. At this point, construction of the object is complete. LISTING L60 Ulustrates the destructor for a TableRef object. In a loop bounded by lines 40-70, all of the objects on this object's tableRefList are destroyed. At line 80, a test is made to determine if the current object has a parent. If so, the function Detach is invoked on the parent object, which removes the current object from the parent tableRefList. This concludes the operation of the destructor. LISTING L61 Ulustrates a function entitled TableNames that recursively generates a string containing names of all the tables in the TableRef hierarchy, separated by commas. LISTING L62 illustrates a routine entitled ColumnNames that generates a list of all the columns in all the tables in a TableRef hierarchy, which may be optionally limited to the primary key columns only. LISTING L63 iUustrates a routine entitled InnerJoins which is used to generate a string representing a TableRef hierarchy as a series of equijoins. LISTING L64 iUustrates a routine entitled JoinCondition which is used to generate a string defining an equijoin between the current TableRef and its parent, if any. LISTING L65 illustrates a routine entitled GatherJoin that is used to generate a string representing all the joins specified by a TableRef hierarchy, which may include outer joins. The routine generates a list of qualified column names to be selected, a Ust of table names, and a where clause representing the join relationships. LISTING L66 illustrates a routine entitled DoDatabaseUpdate which generates a SQL update statement to update the table associated with the current group view element with values from the group view element's current row. Specifically, at line 60, a SQL command is begun that specifies the name of the table to be updated. At line 70, the fUnction FindColumns, shown in LISTING L68, is called to generate a Ust of updates to columns, separated by commas. The columns to be included, and the new value to be used are determined by the fUnction UpdateColumnValues, shown in LISTING L69. At line 90, the fUnction FindColumns is called to generate an appropriate predicate specifying the row to be updated. The columns to be included are specified by the fUnction WherePredicate, which is illustrated in LISTING L70, and separated by AND. At Une 100, a caU to the fUnction ExecuteSQLStrmg is called to update the database. At line 110, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L67 illustrates the routine entitled DoDatabaseDelete that generates a SQL statement to delete the row in the table associated with the current group view element specifed by the group view element's current row. Specifically, at Une 60, a SQL command is begun that specifies the name of the table from which an instance is to be deleted. At line 70, the fUnction FindColumns, shown in LISTING L68, is called to generate generate an appropriate predicate specifying the row to be deleted. The columns to be included are specified by the fUnction WherePredicate, which is iUustrated in LISTING L70. At Une 80, a call to the fUnction ExecuteSQLStrmg is called to update the database. At line 90, an indication of the success or failure of this routine is returned. The routine then terminates. LISTING L68 iUustrates a routine entitled FindColumns that will call a predicate function passed as a parameter with every non-group view element in the current table group view element. If the predicate fUnction returns a non-empty string, it is added to the return value, called "answer". If more than one non-empty value is returned, they wUl be separated in the "answer" string by the string passed as the column separator (colSep) parameter. LISTING L69 illustrates a predicate fUnction entitled UpdateColumnValues that wiU return a string of the form "<column name> = <column value>", if passed a view element which has been updated. LISTING L70 illustrates a predicate fUnction entitled WherePredicate that returns a string of the form "<column name> IS NULL", or "<column name> = <value>", based on the original value of any view element it is passed. An exception to this is view elements specifying potentially large data values. It will be appreciated by those skilled in the art that this serves to implement optimistic locking, and a system which obtained locks when the rows are read from a database would only need to specify primary key values. LISTING L71 illustrates a routine entitled DoDatabaselnsert that generates a SQL statement to insert values in the table associated with the current group view element to the group view element's current row. The function InsertColumns is a predicate function which returns the column name of any view element it has passed. The fUnction Insert Values is a predicate fUnction which returns a string representing the value of any view element it has passed. The predicate functions InsertColumns and InsertValues are set forth in LISTINGS L72 and L73, respectively. Listing L74 sets forth the database schema generated for the object model iUustrated in FIGURE 8. While the preferred embodiment of the invention has been iUustrated and described, it will be appreciated that various changes can be made therein without departing from the spirit and scope of the invention. For example, while the object- oriented programming language as C++ was used extensively to teach the invention, the design tool may be implemented in other languages, and under other operating systems. APPENDIX This appendix contains TABLES T4-T28 that include the C++ classes used to implement the preferred embodiment of the invention. Following the tables are pseudocode listings LISTINGS LI -L74 that depict routines for implementing a preferred embodiment of the invention as described in the Detailed Description section of the patent application. Those skilled in the art will appreciate that the classes and routines depicted are exemplary only, and in at least some of these, other means for carrying out the invention may be accomplished. TABLE T4 TABLE T5 TABLE T6 TABLE T7 TABLE T8 TABLE T9 TABLE T10 TABLE Til TABLE T13 TABLE T14 TABLE T15 SUBSTTTUTE SHEET (RULE 26) TABLE T16 TABLE T17 TABLE TI 8 TABLE T19 TABLE T21 TABLE T23 TABLE T25 TABLE T27 TTTUTE ET RULE 26) TABLE T28 class FormObject { protected: FormObjectO ; public: virtual ~FormObject0 i BOOL IsActionO const ; BOOL IsGridO const ; void Label(const char *pLabel) ; // No single FormObject type can contain all of these, // but all can contain at least one of these. void Insert(FormObject *pChildObject) ; void Insert(Formltem *pChildItem) ; void Insert(PopupMenu *pChildMenu) ; void Insert(MenuItem *pChildItem) ; void Insert(GridColumn *pChildGridColumn) } class Form : public FormObject { public: Form( ViewObject *pViewObj ) ; virtual ~Form0 ; } class Menultem { public: Menultem( ViewObject *pViewObj ) ; ~MenuItemO ; } class PopupMenu : public FormObject { public: PopupMenu( ViewObject *pViewObj ) ; virtual ~PopupMenuO ; } LISTING LI 360 class Grid : public FormObject 370 { 380 public: 390 Grid( ViewObject *pViewObj ) ; 400 virtual ~GridO ; 410 } 420 class Platform : public FormObject 430 { 440 public: 450 Platform( ViewObject *pViewObj ) ; 460 virtual ~Platform() ; 470 } 480 class GroupBo : public FormObject 490 { 500 public: 510 GroupBox( ViewObject *pViewObj ) ; 520 virtual -GroupBoxO ; 530 } 540 class GridColumn 550 { 560 protected: 570 GridColumnO ; 580 public: 590 virtual ~GridColumnO ; 600 } 610 class CheckBoxColumn : public GridColumn 620 { 630 public: 640 CheckBoxColumn( ViewObject *pViewObj ) ; 650 virtual ~CheckBoxColumn() ; 660 } 670 class EditGridColumn : public GridColumn 680 { 690 public: 700 EditGridColumn( ViewObject *pViewObj ) ; 710 virtual -EditGridColumnO ; 720 } LISTING LI (continued) 730 class Formltem 740 { 750 protected: 760 For ltemO ; 770 public: 780 virtual ~FormItem() ; 790 } 800 class ActionButton : public Formltem 810 { 820 public: 830 ActionButton( ViewObject *pViewObj ) ; 840 virtual -ActionButtonO ; 850 } 860 class SearchButton : public Formltem 870 { 880 public: 890 SearchButton( ViewObject *pViewObj ) ; 900 virtual -SearchButtonO ; 910 } 920 class CheckBoxItem : public Formltem 930 { 940 public: 950 CheckBoxItem( ViewObject ♦ pViewObj ) ; 960 virtual -CheckBoxItemO ; 970 } 980 class Editltem : public Formltem 990 { 1000 public: 1010 Editltem( ViewObject *pViewObj ) ; 1020 virtual -EditltemO ; 1030 } LISTING LI (continued) DefineForm( ViewObject *pViewObj, // view object to add to container FormObject *pFormObject // FormObject to add to ) { // Set the title of the FormObject to the view object's caption or name pFormObject->Label(pViewObj->Title0) ; ViewObjectlter iter = pViewObject->Contents0 ; ViewObject *pChild ; FormObject *pNewFormObject ; while (pChild = iter++) { if(pChild->IsActionO) { if(pChild->IsGroupO) { PopupMenu *pNewMenu ; pNewMenu = new PopupMenu(pChild) ; DefineFormφChild, pNewMenu) ; pFormObject->Insert(pNewMenu) ; } else { if(pFormObject->IsActionO) { pFormObject->Insert(new MenuItem(pChild)) ; } else { pFormObject->Insert(new ActionButtonφChild)) ; } } } else if (1 < pChild->MaxCardO) { // multivalued, make a new Grid. // if pFormObj is a form or group box, it's a master grid. // if pFormObj is a grid, the new grid is a detail grid. pNewFormObject = new Grid(pChild) ; DefineForm(pChild, pNewFormObject) ; pFormObject->Insert(pNewFormObject) ; } LISTING L2 430 else if(pFormObject->IsGrid0) 780 if (!(pViewObj->IsRoot0 || pViewObj->IsLink() II pViewObj->IsGroup0)) 790 { 800 // multivalued Simple Value view object (the iter above was empty) 810 pFormObject->Insert(CreateGridColumn(pViewObject)) ; 820 } 830 } LISTING L2 (continued) GridColumn * CreateGridColumn( ViewObject *pViewObj ) { if (BOOL TYPE = p ViewObject->Type0) return new CheckBoxColumn(pViewObj) ; else return new EditGridColumn(pViewObj) ; } LISTING L3 Formltem * CreateFormItem( ViewObject *pViewObj ) { if (BOOLJTYPE ===== p ViewObject->TypeO) return new CheckBoxltem(pViewObj) ; else return new EditItem(pViewObj) ; } LISTING L4 class ReportContainer { protected: ReportContainerO ; public: virtual ~ReportContainerO ; void Title(const char *pTitle) ; void Insert(ReportContainer *pChildContainer) ; void Insert(ReportItem *pChildItem) ; } ; class MVReportContainer : public ReportContainer { public: MVReportContainer( ViewObject *pViewObj ) ; virtual ~MVReportContainer() ; } ; class SVReportContainer : public ReportContainer { SVReportContainer( ViewObject *pViewObj ) ; -SVReporlContainerO ; ReportItem( ViewObject *pViewObj ) ; -ReportltemO ; LISTING L5 DefineReport( ViewObject *pViewObj, // view object to add to container ReportContainer *pContainer // report container to add to ) { // Set the title of the container to the view object's caption or name pContainer->Title(pViewObj->Title0) ; ViewObjectlter iter = pViewObject->Contents() ; ViewObject *pChild ; ReportContainer *pNewContainer ; while (pChild = iter++) { if(pChild->IsActionO) continue ; // reports ignore actions if (1 < pChild->MaxCardO) { // multivalued, make a new MV container pNewContainer = new MVContainer(pChild) ; DefineReportφChild, pNewContainer) ; pContainer->Insert(pNewContainer) ; } else if (pChild->IsLink() || pChild->IsGroupO) { // single valued, make a new SV container pNewContainer = new SVConιainer(pChild) ; DefineReport(pChild, pNewContainer) ; pContainer->Insert(pNewContainer) ; } else { // single valued Simple Value view object pContainer->Insert(new ReportItem(pChild)) ; } } if (!(pViewObj->IsRoot0 II pViewObj->IsLink() || pViewObj->IsGroup0)) { // multivalued Simple Value view object (the iter above was empty) pContainer->Insert(new ReportItem(p ViewObject)) ; } } LISTING L6 /*****************************+******************************+****** * * Class ViewElement - Base class for all nodes and leaves in Runtime Views * * Description: * ViewElement defines the base class for the worker classes of * Runtime Views. The base class defines accessors for some data that * only makes sense in derived classes (e.g., Group View Elements), as * well as accessors and operations useful in the base class. * In general simple ViewElements hold data (which may be user data or * system data such as primary or foreign keys), while Group View * Elements provide aggregation and iteration services to clients of * the Runtime View. * */ class ViewElement { public: enum Roles { COLUMN, // Simple value column ASSOC_GROUP, // Single valued group as container (Semantic Assoc) PR_MARY_KEY, // Single valued attr or group defined as primary key FOREIGN_KEY,// Single valued attr or group defined as foreign key ATTR_TABLE, // Multi valued attribute table (SV. link, or Group) X TABLE, // Intersection table SOJTABLE // SO table } ; enum { ORIGINAL_VALUE = 0, CURRENT VALUE - 1 } ; ViewElement(const ValueComponent *pBaseObj, Group ViewElement *pParentGroup, DataColumn *pColumnDef) ; ViewElement(const ModelComponent *pBaseObj, Group ViewElement *pParentGroup, Table *pTable) ; ViewElement(const ModelComponent *pBaseObj, GroupViewElement *pParentGroup) ; ViewElement(Group ViewElement *pParentGroup, DataColumn *pColumnDef) ; ViewElement(const Value ViewComponent *pViewObj, GroupViewElement *pParentGroup, DataColumn *pColumnDef) ; ViewElement(const ViewObject *pViewObj, GroupViewElement *pParentGroup, 0 Table *pTable) ; 0 ViewElement(const ViewObject *pViewObj, 0 GroupViewElement *pParentGroup) ; LISTING L7A -118- 480 virtual -ViewElementQ i 490 // Conversion function - contents list for groups, empty otherwise. 500 virtual operator ViewElementlterO const ; 510 virtual ViewElementlter ContentsQ const ; 520 // Persistent permissions 530 virtual BOOL IsDeleteAllowed() const ; 540 virtual BOOL IsNewAllowedO const ; 550 virtual BOOL IsNulIAllowedO const ; 560 virtual ConnectPower::Powers ConnectPowerO const ; IsColumnO const ; IsGroupO const ; IsTableO const ; IsTableGroupO const ; IsIntersectionTableO const ; IsLinkO const ; 640 // ViewElement Relationships in Hierarchy 650 virtual ViewElement *PrimaryKeyO const ; 660 ViewElement *KeyPair0 const ; 670 GroupViewElement *ParentO const ; 680 GroupViewElement *ParentTableGroupO const ; 690 virtual GroupViewElement *ForeignKey(const ViewElement *pOther) const ; 700 virtual void SetKeyPair(Group ViewElement *pRefsrencedGroup) ; 710 virtual void Configure(ViewObject *pViewObj) ; 720 virtual void ParamJoin(String ..predicate, BOOL IFKValue) const ; *Value(BOOL fUpdateOK = TRUE) const ; Value(Variant *newVal) ; IsNull(BOOL fUpdateOK = TRUE) const ; IsUpdatedO const ; StringValue( BOOL fUpdateOK = TRUE ) const ; CopyKeyO ; &PredicateO const ; &Predicate(const String &newPred) ; SubQueryPredicate(String &predicate) const ; 830 // Persistent Data Accessors 840 unsigned long ObjectldO const ; 850 unsigned long ViewObjectldO const ; 860 const String &Name0 const ; // column or table name 870 unsigned long MinCardO const ; 880 unsigned long MaxCardO const ; LISTING L7A (continued) 1250 private: 1260 // Default assignment operator is private and not implemented... 1270 ViewElement &operator=(const ViewElement &other) ; 1280 } ; LISTING L7A (continued) * * Class GroupViewElement - Container & grouping class for ViewElements * * Description: * Group View Elements provide aggregation and iteration services to * clients of the Runtime View. */ class GroupViewElement : public ViewElement { public: Group ViewElement(const ModelComponent *pBaseObj, GroupViewElement *pParentGroup, Table *pBaseTable) ; Group ViewElement(const GroupComponent *pBaseObj, GroupViewElement *pParentGroup) ; Group ViewElement(const ModelComponent *pBaseObj GroupViewElement *pParentGroup, DataColumn *pColumnDef) ; Group ViewElement(const ViewObject *pViewObj GroupViewElement *pParentGroup, Table *pBaseTable) ; Group ViewElement(const Group ViewObject *pViewObj GroupViewElement *pParentGroup) ; virtual -Group ViewElementO ; // Conversion function - contents list for groups, empty otherwise. virtual operator ViewElementlterO const ; virtual ViewElementlter ContentsO const ; // Persistent Permissions virtual BOOL IsDeleteAllowedO const ; virtual BOOL IsNewAllowedO const ; virtual ConnectPower "Powers ConnectPowerO const ; // ViewElement Relationships in Hierarchy virtual ViewElement *PrimaryKeyO const ; virtual GroupViewElement *ForeignKey(const ViewElement *pOther) const ; BOOL DependsOn(Group ViewElement *pOtherGroup) ; // Data Integrity Support ErrorCode ValidateCountsAndCardsO ; LISTING L7B 390 // Performing database query 400 ErrorCode Query(const char *newPredicate, 410 BOOL fUseConnectPower) ; 420 ErrorCode FindQ ; 430 ErrorCode Select(BOOL fExtendedRead, 440 BOOL fParentConstraint, 450 BOOL fUseConnectPower) ; 460 void P__entInstancePredicate(String &predicates) const ; 470 void Para Join(String Apredicate, BOOL IFKValue) const : 480 String ConnectPowerPredicateO const ; 490 int DefinePredicateDown(String ..predicate, 500 BOOL fExtendedRead, 510 TableRef &tableRef) const ; 520 int JoinPredicate(String &predicate, 530 BOOL fExtendedRead, 540 TableRef &tableRef) const ; 550 int DefinePredicateUp(ViewElement ♦ pLastView, 560 String &predicates, 570 BOOL fExtendedRead, 580 TableRef AtableRef) const ; 590 // Cursor Methods 600 ErrorCode FirstO ; 610 ErrorCode LastO ; 620 ErrorCode NextO ; 630 ErrorCode PreviousO ; 640 BOOL AtBeginningO const; 650 BOOL AtEndQ const; 660 unsigned long GetCountO ; 670 unsigned long GetPairCountO ; 680 ErrorCode SetCurrent(CursorPosition newCurrent) ; 690 CursorPosition GetCurrentO ; 700 ErrorCode NewRowO ; 710 ErrorCode CopyQueryRowQ ; UpdateO ; Connect(BOOL fUseQuery) ; DisconnectO ; InsertO ; DeleteO ; DisconnectAllO ; DeleteAllO ; LISTING L7B (continued) -122- 800 ErrorCode DoDatabaseUpdateO ; 810 ErrorCode DoDatabaseDeleteO ; 820 ErrorCode DoDatabaselnsertO ; 830 String FindColumns(String (*pPredicateFunc)(ViewElement *), 840 const char *colSep) ; 850 // Support function for Intersection Table 860 GroupViewElement *XTableChild0 const; 870 // View construction... 880 void DefineRuntimeView(ModelObject *pModelObj, 890 Schema &theSchema) ; 900 void DefineRuntimeView(ViewObject *pViewObj, 910 Schema &theSchema) ; 920 GroupViewElement *CreateParentGroup(ModelObject ♦ pTargetModelObject, 930 Schema &theSchema) ; 940 void AddPrimaryKeyO ; 950 void AddForeignKey(ModelObject ♦ pLink, 960 GroupViewElement *pReferencedGroup) ; 970 virtual void SetKeyPair(Group ViewElement *pReferencedGroup) ; 980 virtual void Configure(ViewObject *pViewObj) ; 990 void AddRelatedTable(ViewElement *pFKVE, 1000 GroupViewElement *pRelatedGroup) ; 1010 ViewElement ♦ Lookup ViewElement(ColumnDef *pPKColumn) ; 1020 ViewElement ♦ Lookup ViewElement(ModelObject *pObj) ; 1030 ViewElement ♦ Lookup ViewElement(ViewObject ♦ pChild) ; 1040 GroupViewElement ♦LookupGroupViewElement(ModelObject *pObj) ; 1050 GroupViewElement ♦ LookupGroupViewElement(ViewObject *pChild) ; 1060 // Persistent Data Access 1070 unsigned long MinCountO const ; 1080 unsigned long MaxCountO const ; 1090 unsigned long PairMinCardO const ; 1100 unsigned long PairMaxCardO const ; 1110 ViewElememlter ForeignRelationsO const ; 1120 Table *Table0 ; 1130 1140 LISTING L7B (continued) 1150 protected: 1160 // Data Members 1170 ViewElement ♦ pPrimaryKey ; 1180 ConnectPower::Powers connectPower ; 1190 BOOL disconnectPower ; 1200 BOOL fDeleteAllowed ; 1210 BOOL fNewAllowed ; 1220 unsigned long minCount ; 1230 unsigned long maxCount ; 1240 ViewElementList contents ; 1250 ViewElementListrelatedTables ; 1260 ViewElementMap foreignKeys ; 1270 unsigned long pairMinCard ; 1280 unsigned long pairMaxCard ; 1290 Table ♦ pTable ; 1300 private: 1310 // Default ctor and op= are private and will not be implemented... 1320 GroupViewElement &operator=(const GroupViewElement &other) ; 1330 } ; LISTING L7B (continued) ViewElement: :ViewElement( const ValueComponent ♦ pBaseObj, GroupViewElement *pParentGroup, DataColumn *pColumnDef ) : objectID( pBaseObj->Objectid0 ), viewObjID( OL ), n_me(pColu_nnDef->NameO ), // database column name minCard( pBaseObj->MinCard0 ), // may be 1 or 0 maxCard( lUL ), // force this to be 1 maxLength( pColumnDef->MaxLengthO ), // database column size scale( pColumnDef->ScaleO ), // scale (for numeric types) logicalLength( pBaseObj->LengthO ), // size as modeled dataType( pColumnDef->DataTypeO ), // in-memory datatype dbDataType( pColumnDef->DBDataT>peO ), // database data type allowedAction( pBaseObj->AllowedAction0 ), // constant, change, readonly role( Roles::COLUMN ), idStatus( pBaseObj->IDStatusO ), // none, unique, non-unique valueType( pBaseObj->ValueType0 ), // type as modeled dataSource( pBaseObj->Source0 ), // user, formula, both keyPah NULL ), parent( pParentGroup ), parentTableGroup( NULL ), initialValue( pBaseObj->InitialValue0 ), // a script as a string recomputeExpr( pBaseObj->RecomputeExpr() ), // a script as a string pColumn(pColumnDef) { parentTableGroup = ((!parent->IsTableO) ? parent->ParenfTableGroupO : parent) ; if ( parentTableGroup->Object_d() = objectID ) { // This must be the data for a multivalued SV - don't allow NULLs. minCard = 1; } } LISTING L8 ViewElement::ViewElement( const ModelComponent *pBaseObj, GroupViewElement *pParentGroup, Table *pTable ) : objectID( pBaseObj->ObjectId0 ), viewObj_D( 0L ), name( pTable->NameO ), // database table name minCa_d( pBaseObj->MinCardO ), maxCard( pBaseObj->MaxCardO ), maxLength( OL ), scale( O ), logicalLength( OL ), dataType( CT_NULL ), dbDataType( SQLDBType: :DBT_NULL ), allowedAction( Action::Actions::CHANGE ), role( Roles: :COLUMN ), // will be changed below idStatus( pBaseObj->IDStarusO ), valueType( ValueType::NONE ), dataSource( Source: :NONE ), keyPair( NULL ), parent( pParentGroup ), parentTableGroup( NULL ), pColumn( NULL ) { parentTableGroup = ((parent && !parent->IsTableO) ? parent->ParentTableGroupO : parent) ; } LISTING L9 GroupViewElement: :GroupViewElement( const ModelComponent *pBaseObj, GroupViewElement *pParentGroup, Table *pBaseTable ) : ViewElement(pBaseObj, pParentGroup, pBaseTable), pPrimaryKey( NULL ), connectPower( ConnectPower: :Powers: :NONE ), fDeleteAllowed( TRUE ), fNewAllowed( TRUE ), minCount( 0UL ), maxCount( ~OUL ), pairMinCard( 0UL ), pairMaxCard( 0UL ), pTable( pBaseTable ) { if (Iparent || pBaseObj->IsLinkO) { role = SOJTABLE ; if (parent) { connectPower = pBaseObj->ConnectPower() ; disconnectPower = pBaseObj->DisconnectPower() ; IDeleteAllowed = pBaseObj->IsDeleteAllowedO ; INewAllowed = pBaseObj->IsNewAllowedO ; pairMinCard = pBaseObj->PairObject()->MinCard0 ; pairMaxCard = pBaseObj->PairObject0->MaxCa_d0 ; } } else { role = ATTRJTABLE ; if(pBaseObj->IsGroup0) { minCount = pBaseObj->MinCount() ; maxCount = pBaseObj->MaxCount() ; IDeleteAllowed = pBaseObj->IsDeleteAllowedO ; INewAllowed = pBaseObj->IsNewAllowed() ; } else { IDeleteAllowed = Actions: :CHANGE = pBaseObj->AllowedAction0 ; INewAllowed = Actions: :READONLY != pBaseObj->AllowedActionO ; } } } LISTING L10 ViewElement::ViewElement( const ModelComponent *pBaseObj, GroupViewElement *pParentGroup ) : object_D( pBaseObj->Objectid0 ), viewObjID( 0L ), minCard( pBaseObj->MinCard() ), maxCard( pBaseObj->MaxCard0 ), maxLength( 0L ), scale( 0 ), logicalLength( OL ), dataType( CTJNULL ), dbDataType( SQLDBType: :DBT_NULL ), allowedAction( Action::Actions::CHANGE ), role(Roles::COLUMN ), idStatus( pBaseObj->_DStatusO ), valueType( ValueType::NONE ), dataSource( Source: :NONE ), keyPair( NULL ), parent( pParentGroup ), parentTableGroup( NULL ), pColu n( NULL ) { parentTableGroup = ((!parent->IsTableO) ? parent->ParenfTableGroupO : parent) ; } LISTING Lll Group ViewElement::GroupViewElement( const GroupComponent *pBaseObj, GroupViewElement *pParentGroup ) : ViewElement(pBaseObj, pParentGroup), pPrimaryKey( NULL ), connectPower( ConnectPower::Powers::NONE ), _DeleteAllowed( pBaseObj->IsDeleteAIlowedO ), INewAllowed( pBaseObj->IsNewAIlowedO ), minCount( pBaseObj->MinCountO ), maxCount( pBaseObj->MaxCountO ), pairMinCard( OUL ), pairMaxCard( OUL ), pTable( NULL ) { role = ASSOC_GROUP ; } LISTING L12 CreateCanonicalRuntimeViews( Model &theModel ) { SemanticObjectlter iter = theModel ; SemanticObject *pSO ; GroupViewElement *pGVE ; Schema &theSchema = theModel. SchemaO ; while (pSO = iter++) { pGVE = new Group ViewElement( pSO, NULL, theSchema.Lookup(pSO) ) ; pGVE->DefineRuntimeView(pSO, theSchema) ; } } LISTING L13 GroupViewElement: :DefineRuntimeView( ModelObject *pModelObj, Schema &theSchema ) { ModelObjectlter iter = pModelObj->Contents0 ; ModelObject *pChild ; ViewElement *pVE ; GroupViewElement *pGVE ; Table *pTable ; if(IsTableGroupO) { AddPrimaryKeyO ; if(TableO->IsIntersectionTableO) { pTable = theSchema.Lookup(pModelObj->ReferencedSO0) ; pGVE = new Group ViewElement(pModelObj, this, pTable) ; contents += pGVE ; pGVE->DefineRuntimeView(pModelObj, theSchema) ; AddForeignKey(pModelObj, pGVE) ; AddForeignKey(pModelObj->PairObject0, parentTableGroup) ; return ; } LISTING L14 240 if(ParentO) 250 { 260 if(Table0->IsSemanticObjectTable0) 270 { 280 // add groups down to my modelObject's pair... 290 ModelObject *pPairObj = pModelObj->PairObject0 ; 300 ModelObject *pSO = pModelObj->ReferencedSO0 ; 310 GroupViewElement *pLinkParent = this ; 320 if (pSO != pPairObj->Parent0) 330 { 340 pLinkParent = CreateParentGroupφPairObject, theSchema) ; 350 } 360 if (pLinkParent->Table0->HasForeignKey(pPairObj)) 370 { 380 pLinkParent->AddForeignKey(pPairObj, parentTableGroup) ; 390 } 400 return ; 410 } 420 if (Table0->HasForeignKey(parentTableGroup->ModelObject0)) 430 { 440 AddForeignKey(parentTableGroup->ModelObject0, parentTableGroup) ; 450 } 460 } 470 } 480 while (pChild = iter++) 490 { 500 if(pChild->IsLinkO) 510 { 520 // Check for intersection tables... 530 pTable = theSchema.Lookup(pChild) ; 540 if(lpTable) 550 pTable = theSchema.Lookup(pChild->ReferencedSO0) 560 pGVE == new Group ViewElement(pChild, this, pTable) ; 570 contents += pGVE ; 580 pGVE->DefineRuntimeView(pChild, theSchema) ; 590 if (Table0->HasForeignKey(pChild->ReferencedSO0)) 600 AddForeignKey(pChild, pGVE) ; 610 } LISTING L14 (continued) 620 else if (1 < pChild->MaxCardO) 630 { 40 // Multi-valued Group or S V 50 pGVE = new Grou P ViewElement(pChild, this, theSchema.Lookup(pChild)) ; ^60 contents += pGVE ; 670 680 pGVE->DefineRuntimeView(pChild, theSchema) ; 690 else if (pChild->IsGroupO) 700 { 710 // Single- Valued group... 720 if (!(pGVE = LookupGroupViewElement(pChild))) 730 { 740 pGVE = new Group ViewElement(pChild, this) ; 750 contents += pGVE ; 760 } 770 pGVE->DefineRuntimeView(pChild, theSchema) ; 780 } 790 else if (!(pVE = LookupViewElement(pChild))) 800 810 // Must be a single-valued S V... 820 pVE = new ViewElement(pChild, this, TableO->Lookup(pChild)) ; 830 ccoonntteennttss + +== p _VVEE ; • 840 850 860 870 if (!(pModelObj->IsLink 0 II pModelObj->IsGroup 0 ) && IsTableGroupQ) 880 // Add column for multi-valued SVs 900 « contents +== p pVV_E- E • ,emem(PMθdeIObJ ' ^ ^O-LookupφModelObj)) ; 910 } 920 } LISTING L14 (continued) GroupViewElement * GroupViewElement: :CreateParentGroup( ModelObject *pTargetModeIObject, Schema &theSchema ) { ModelObject *pNextModelObj = pTargetModelObject->Parent0 ; GroupViewElement *pNextGVE ; if (pBaseObj = pNextModelObj) return this ; while (pBaseObj != pNextModelObj->Parent0) pNextModelObj = pNextModelObj->Parent0 ; if (pTable = theSchema.Lookup(pNextModelObj)) { pNextGVE = new Group ViewElement(pNextModelObj, this, pTable) ; pNextGVE->AddPrimaryKeyO ; pNextGVE->AddForeignKey(TableGroup0->ModelObject0, this) ; } else { pNextGVE = new Group ViewElement(pNextModelObj, this) ; } contents += pNextGVE ; if (pBaseObj != pTargetModelObject->ParentO) { pNextGVE = pNexlGVE->CreateParentGroup(pTargetModelObject, theSchema) ; } return pNextGVE ; } LISTING L15 void GroupViewElement: :AddPrimaryKeyO { DataColumn *pPK = pTable->GetPKCoIumn() ; ModelObject *pModelObj ; ViewElement *pVE ; if (pModelObj = pPK->ModelObject0) if(pModelObj->IsGroupO) pVE = new Group ViewElementφModelObj, this, pPK) ; else pVE = new ViewElementφModelObj, this, pPK) ; else { pVE = new ViewEIement(this, pPK) ; } contents += pVE ; } LISTING L16 void GroupViewElement: :AddForeignKey( ModelObject *pLink, GroupViewElement *pReferencedGroup ) { DataColumn *pFK = pTable->GetFKColumn(pLink) ; ViewElement *pVE ; if(pFK->IsGroupO) { pVE = new Group ViewElement(pLink, this, pFK) ; } else { pVE = new ViewElement(pLink, this, pFK) ; } pVE->SetKeyPair(pReferencedGroup) ; AddRelatedTable(pVE, pReferencedGroup) ; pReferencedGroup->AddRelatedTable(pVE, this) ; contents += pVE ; > LISTING L17 ViewElement::ViewElement( GroupViewElement *pParentGroup, DataColumn *pColumnDef ) : objectID( pColumnDef->ObjectId0 ), // 0 unless data primary key viewObjID( OL ), name( pColumnDef->NameO ), // database column name minCard( pColumnDef->IsPrimaryKeyO ? 1UL : // surrogates are required pColumnDef->MinCardO ), // but FKs might not be maxCard( 1UL ), // force this to be 1 maxLength( pColumnDef->MaxLengthO ) > // database column size scale( pColumnDef->ScaleO ), logicaILength( pColumnDef->MaxLengthO ), dataType( pColumnDef->DataTypeO ), // in-memory datatype dbDataType( pColumnDef->DBDataTypeO ), // database data type allowedAction( pColumnDef->IsPrimaryKeyO 7 Action::CONSTANT : // surrogates don't change Action: :CHANGE ), // but foreign keys can role( Roles: :COLUMN ), idStatus( pColumnDef->IsPrimaryKeyO ? IDStatus: :UNIQUE : // surrogates are unique IDStatus: :NON_UNIQUE ), // FKs might not be valueType( pColumnDef->DataTypeO ), dataSource( Source: :USER ), keyPair( NULL ), parent( pParentGroup ), parentTableGroup( NULL ), pColumn( pColumnDef) { parentTableGroup = (φarent && !parent->IsTableO) ? parent->ParentTableGroupO : parent) ; } LISTING L18 Group ViewElement::GroupViewElement( const ModelComponent ♦ pBaseObj GroupViewElement *pParenιGroup, DataColumn *pColumnDef ) : ViewElementφBaseObj, pParentGroup, pColumnDef), pPrimaryKey( NULL ), connectPower( ConnectPower: :Powers: :NONE ), _DeleteAllowed( TRUE ), fNewAllowed( TRUE ), minCount( OUL ), maxCount( -OUL ), pairMinCard( OUL ), pairMaxCard( OUL ), pTable(NULL ) { role = ASSOC_GROUP ; connectPower = pBaseObj->ConnectPower() ; disconnectPower = pBaseObj->DisconnectPower0 ; fDeleteAllowed = pBaseObj->IsDeleteAllowed0 ; INewAllowed = pBaseObj->IsNewAllowed() ; pairMinCard = pBaseObj->PairObject0->MinCard0 ; pairMaxCard = pBaseObj->PairObject0->MaxCard0 ; minCount = pColumnDef->ModelObject0->MinCount0 ; maxCount = pColumnDef->ModelObject0->MaxCount0 ; DataColumnlter iter = pColumnDef->ContentsO ; DataColumn *pFKPart ; ViewElement *pVE ; while φFKPart = iter++) { ifφColumnDef->IsPrimaryKeyO) { pVE = new ViewElementφFKPart->ModelObject(), this, pFKPart) ; } else { pVE == new ViewElement(this, pFKPart) ; } contents += pVE ; } } LISTING LI 9 void ViewElement: :SetKeyPair( GroupViewElement *pReferencedGroup ) { keyPair = pReferencedGroup->LookupViewElementφColumn->KeyPairO) ; } LISTING L20 void GroupViewElement: :SetKeyPair( GroupViewElement ♦ pReferencedGroup ) { ViewElement::SetKeyPairφReferencedGroup) ; ViewElementlter iter = contents ; ViewElement *pVE ; while φVE = iter++) { pVE->SetKeyPairφReferencedGroup) ; } } LISTING L21 ViewElement * GroupViewElement: :Lookup ViewElement( ColumnDef*pPKColumn ) { ViewElementlter iter = contents ; ViewElement ♦ pVE ; while ( pVE = iter++ ) { if φVE->DataColumn() = pPKColumn) break ; } return pVE ; } LISTING L22 void GroupViewElement: : AddRelatedTable( ViewElement *pFKVE, GroupViewElement ♦ pRelatedGroup ) { relatedTables += pRelatedGroup ; foreignKeys[pRelatedGroup] = pFKVE ; } LISTING L23 ViewElement * GroupViewElement: :Lookup ViewElement( ModelObject *pObj ) { ViewElementlter iter = contents ; ViewElement *pVE ; while ( pVE = iter-H- ) { if φVE->ObjectId0 = pObj->ObjectId()) break ; } return pVE ; } LISTING L24 GroupViewElement * GroupViewElement: :LookupGroupViewElement( ModelObject *pObj ) { ViewElementlter iter = contents ; ViewElement *pVE ; while ( pVE == iter++ ) { if φVE->IsGroup0 && pVE->ObjectId0 = pObj->ObjectId0) break ; } return (GroupViewElement *)pVE ; } LISTING L25 ViewElement: :ViewElement( const ValueViewComponent *pViewObj, GroupViewElement ♦ pParentGroup, DataColumn *pColι_mnDef ) : objectID( pViewObj->BaseObj0->ObjectId() ), viewObjID( pViewObj->ObjectId0 ), name( pColumnDef->NameO ), // database column name minCard( pViewObj->BaseObj0->MinCard0 ), // may be 1 or 0 maxCard( lUL ), // force this to be 1 maxLength( pColumnDef->MaxLength() ), // database column size scale( pColumnDef->ScaleO ), // scale (for numeric types) logicalLength( pViewObj->BaseObj0- Length() ), // size as modeled dataType( pColumnDef->DataTypeO ), // in-memory datatype dbDataType( pColumnDef->DBDataTypeO ), // database data type allowedAction( pViewObj->AllowedActionO ), // constant, change, readonly role( Roles: :COLUMN ), idStatus( pViewObj->BaseObj0->IDStatus0 ), // none, unique, non-unique valueType( pViewObj->BaseObj()->ValueType0 ), // type as modeled dataSource( pViewObj->BaseObjO->SourceO ), // user, formula, both keyPair( NULL ), parent( pParentGroup ), parentTableGroup( NULL ), initialValue( pViewObj->BaseObj0->InitialValue() ), // a script as a string recomputeExpr( pViewObj^BaseObJO^RecomputeExprO ), // a script as a string pColumn( pColumnDef) { parentTableGroup = ((!parent->IsTableO) ? parent->ParentTableGroupO : parent) ; if ( parentTableGroup->ObjectId() == objectID ) { // This must be the data for a multivalued SV - don't allow NULLs. minCard = 1; } } LISTING L26 ViewElement: :ViewElement( const ViewObject *pViewObj, GroupViewElement ♦ pParentGroup, Table *pTable ) : objectπ>( pViewObj->Ba_eObj0->ObjectId0 ), viewObjID( pViewObj->ObjectId0 ), name( pTable->NameO ), // database table name minCard( pViewObj->BaseObj0->MinCard0 ), maxCard( pViewObj->BaseObj0->MaxCard0 ), maxLength( 0L ), scale(O ), logicalLength( 0L ), dataType( CT NULL ), dbDataType( SQLDBType: :DBT_NULL ), allowedAction( Action::Actions::CHANGE ), role(Roles::COLUMN ), // will be changed below idStatus( pViewObj->BaseObJ0->IDStatus0 ), valueTyρe( ValueType::NONE ), dataSource( Source: :NONE ), keyPair(NULL ), parent( pParentGroup ), parentTableGroup( NULL ), pColumn( NULL ) { parentTableGroup = (φarent && !parent->IsTable()) ? parent->ParentTableGroupO : parent) ; } LISTING L27 Group ViewElement::GroupViewElement( const ViewObject *pViewObj GroupViewElement *pParentGroup, Table *pBaseTable ) : ViewElementφViewObj, pParentGroup, pBaseTable), pPrimaryKey( NULL ), connectPower( ConnectPower::Powers::NONE ), _DeleteAllowed( TRUE ), fNewAllowed(TRUE ), minCount( OUL ), maxCount( ~OUL ), ρairMinCard( OUL ), pairMaxCard( OUL ), pTable( pBaseTable ) { if ( ( parent || pViewObj->BaseObjO->IsLinkO) { role = SOJTABLE ; if φarent) { connectPower = pViewObj->ConnectPowerO ; disconnectPower = pViewObj->DisconnectPower() ; IDeleteAllowed = pViewObj->IsDeleteAllowedO ; fNewAllowed = pViewObj->IsNewAllowedO ; pairMinCard = pViewObj->BaseObj0->PairObject0->MinCard0 ; pairMaxCard = pViewObj->BaseObj0->PairObject0->MaxCard0 ; } } else { role = ATTRJTABLE ; ifφViewObj->BaseObjO->IsGroupO) { minCount = pViewObj->BaseObjO->MinCount() ; maxCount = pViewObj->BaseObjO->MaxCountO ; IDeleteAllowed = pViewObj->IsDeleteAllowedO ; fNewAllowed = pViewObj->IsNewAllowed0 ; } else { IDeleteAllowed = Actions::CHANGE == pViewObj->AllowedAction() ; INewAllowed = Actions: :READONLY != pViewObj->AllowedActionO ; } } } LISTING L28 ViewElement: :ViewElement( const ViewObject *pViewObj, GroupViewElement *pParentGroup ) : objectID( pViewObj->BaseObj0->Objectid0 ), viewObjID( pViewObj->ObjectId0 ), minCard( pViewObj->BaseObj0->MinCard0 ), maxCard( pViewObj->BaseObj0->MaxCard0 ), maxLength( OL ), scale( 0 ), logicalLength( 0L ), dataType( CT_NULL ), dbDataType( SQLDBType: :DBTJNULL ), allowedAction( Action: : Actions: -CHANGE ), role(Roles::COLUMN ), idStatus( pViewObj->BaseObj0->IDStatus0 ), valueType( ValueType::NONE ), dataSource( Source::NONE ), keyPair( NULL ), parent( pParentGroup ), parentTableGroup( NULL ), pColumn( NULL ) { parentTableGroup = ((!parent->IsTableO) ? parent->ParentTableGroupO : parent) ; } LISTING L29 Group ViewElement: :GroupViewElement( const Group ViewObject *pViewObj GroupViewElement *pParentGroup ) : ViewElementφViewObj, pParentGroup), pPrimaxyKey( NULL ), connectPower( ConnectPower: :Powers: :NONE ), _DeleteAllowed( pViewObj->IsDeleteAllowed0 ), fNewAllowed( pViewObj->IsNewAllowed0 ), minCount( pViewObj->BaseObjO->MinCount() ), maxCount( pViewObj->BaseObj0->MaxCount0 ), pairMinCard( OUL ), pairMaxCard( OUL ), pTable( NULL ) { role = ASSOC_GROUP ; } LISTING L30 CreateFormRuntimeViews( Model &theModel ) { ObjectViewIter iter = theModel ; ObjectView *pView ; GroupViewElement *pGVE ; Schema &theSchema = theModel. SchemaO ; while φView = iter++) { pGVE = new Group ViewElement( pView, NULL, theSchema.LookupφView->BaseObj0) ) ; pGVE->DefineRuntimeViewφView, theSchema) ; } } LISTING L31 GroupViewElement: :DefineRuntime View( ViewObject *pViewObj, Schema &theSchema ) { ViewObjectlter iter = pViewObj->Contents() ; ViewObject *pChild ; ViewElement *pVE ; GroupViewElement *pGVE ; Table *pTable ; if(IsTableGroupO) { AddPrimaryKeyO ; if(TableO->IsIntersectionTableO) { pTable = theSchema.LookupφViewObj->BaseObJ0->ReferencedSO0) ; pGVE = new Group ViewElementφViewObj, this, pTable) ; contents += pGVE ; pGVE->DefιneRuntimeViewφViewObj, theSchema) ; AddForeignKeyφViewObj->BaseObj0, pGVE) ; AddForeignKeyφViewObj->BaseObjO->PairObjectO, parentTableGroup) ; return ; } LISTING L32 if(Parent0) { if (Table0->IsSemanticObjectTable0) { LISTING L32 (continued) 640 else if (1 < pChild->MaxCardO) 650 { 660 // Multi-valued Group or S V 670 pGVE = new Group ViewElementφChild, this, 680 theSchema.LookupφChild->BaseObj0)) ; 690 contents += pGVE ; 700 pGVE->DefineRuntimeViewφChild, theSchema) ; 710 } 720 else ifφChild->IsGroupO) 730 { 740 // Single-Valued group... 750 if φGVE = LookupGroupViewElementφChild->BaseObjO)) 760 { 770 pGVE->ConfigureφChild) ; 780 } 790 else 800 { 810 pGVE = new GroupViewElementφChild, this) ; 820 contents += pGVE ; 830 } 840 pGVE->DefineRuntimeViewφChild, theSchema) ; 850 } 860 else // Must be a single-valued S V... 870 if φ VE = LookupViewElementφChild)) 880 { 890 pVE->ConfigureφChild) ; 900 } 910 else 920 { 930 pVE = new ViewElementφChild, this, 940 Table0->LookupφChild->BaseObj0)) ; 950 contents += pVE ; 960 } 970 } 980 if (!φViewObj->I-Link0 || pViewObj->IsGroup0) && IsTableGroupO ) 990 { 1000 // Add column for multi-valued S Vs 1010 pVE = new ViewElementφViewObj, this, Table0->LookupφViewObj->BaseObJ0)); 1020 contents += pVE ; 1030 } 1040 } LISTING L32 (continued) void ViewElement: :Configure( ViewObject *pViewObj ) { viewObjED = pViewObj->ObjectId() ; allowedActiσn = pViewObj->AllowedAction0 ; } LISTING L33 void GroupViewElement::Configure( ViewObject *pViewObj ) { ViewElement::ConfigureφViewObj) ; IDeleteAllowed = pViewObj->IsDeleteAllowedO ; fNewAllowed = pViewObj->IsNewAllowed0 ; } LISTING L34 ViewElement * GroupViewElement: :Lookup ViewElement( ViewObject *pChild ) { ViewElementlter iter = contents ; ViewElement *pVE ; while ( pVE = iter++ ) { if φVE->ViewObjecαd0 = pCluld->ObjectId0 || pVE->ObjectId0 = pChild->BaseObj0->ObjectId0) brea ; } return pVE ; } LISTING L35 GroupViewElement * GroupViewElement: :LookupGroup ViewElement( ViewObject ♦ pChild return (GroupViewElement *)pVE ; } LISTING L36 ErrorCode GroupViewElement: :UpdateO { ErrorCode err ; if (Action: : Actions: :READONLY = allowedAction) { return ERROR_UPDATE_NOT_ALLO WED ; } if ( XJTABLE = role ) { err = XTableChild()->UpdateO ; } else { // check that this group is OK... err = ValidateCountsAndCardsO ; if(lerr) { err = DoDatabaseUpdateO ; } } return err ; } LISTING L37 GroupViewElement * GroupViewElement: :XTableChildO const { GroupViewElement *pGVE = NULL; ViewElementlter fklter = foreignKeys ; ViewElement *pFK ; while ( IpGVE && NULL != φFK = fklter++) ) { if (this == pFK->KeyPairO->ParentTableGroupO->ParentTableGroupO) pGVE = pFK->KeyPairO->ParenfTableGroupO ; > return pGVE ; } LISTING L38 LISTING L39 ErrorCode GroupViewElement: disconnect 0 { ErrorCode err = SUCCESS; // Here we only check the back link cardinality - the cardinality of this // will be checked in UpdateO if φairMinCard && (1 == pairMaxCard || pairMinCard >= GetPairCountO)) { return RUNT E DISCONNECT NOT_ALLOWED ; } if ( XJTABLE — role ) { // this GVE has both of the foreign keys involved, // so all we need to do is delete the current row of this GVE. err = DeleteO ; } else { ViewElement *pFK = foreignKeys! parentTableGroup ] ; err = pFK->Value(NULL) ; } return er ; > LISTING L40 ErrorCode GroupViewElement: .'InsertO { ErrorCode err ; // first, check static constraints... if ( IsIntersectionTableO II IIsTableO ) return ERROR_INVAL_D_USER_INSERT ; if( IIsNewAllowedO ) return ERROR_INSERT_NOT_ALLO WED ; // next, check that this group is OK... err = ValidateCountsAndCardsO ; if(lerr) { if ( ParentO && IIsLinkO ) { err = parentTableGroup->Connect( this ) ; } if(!err) err = DoDatabaselnsertO ; } return err ; } LISTING L41 ErrorCode Group ViewElement::ValidateCountsAndCardsO { ErrorCode err = SUCCESS ; ViewElementlter iter = contents ; ViewElement *pVE ; unsigned long nonNullCount = 0; // Iterate across contents while ( pVE = iter++ ) { if(l < pVE->MaxCardO) { unsigned long count = pVE->GetCountO ; if (count > pVE->MaxCard0) { err = ERROR_MAX_CARD_EXCEEDED ; break ; } if (count < pVE->MinCard0) { err = ERROR_MIN_CARD_UNMET ; break ; if (count) nonNullCount++ } else { ifφVE->IsNull0) { ifφVE->MinCardO) { err = ERROR_REQUIRED_ITEM_MISSING ; break ; > } LISTING L42 370 else 380 { 390 ifφVE->ObjectIdO) 400 nonNullCount-H- ; 410 if ( !pVE->IsTableO && pVE->IsGroupO ) 420 { 430 // Validate any contained single-valued groups.. 440 if (err = pVE->ValidateCountsAndCardsO) 450 break ; 460 } 470 } 480 } 490 } 500 if(lerr) 510 { 520 if (nonNullCount != MaxCountO) 530 { 540 if (nonNullCount > MaxCountO) 550 { 560 err - ERROR_MAX_COUNT EXCEEDED ; 570 } 580 else if (nonNullCount < MinCountO) 590 { 600 err - ERROR_MIN_COUNT_UNMET ; 610 > 620 } 630 } 640 return err ; 650 } LISTING L42 (continued) ErrorCode GroupViewElement::DeleteO { ErrorCode err = SUCCESS; if ( lIsIntersectionTableO ) { Group ViewElementlter iter = relatedTables ; GroupViewElement *pGVE ; while ( pGVE = iter+ ) { if( pGVE->IsLinkO ) { err = pGVE->DisconnectA110 ; } else if ( parentTableGroup 1= pGVE ) { err = pGVE->DeleteAH0 ; } if (err) break ; } } if(lerr) err = DoDatabaseDeleteQ ; return err; } LISTING L43 SUBSTTTUTE SHEET (RULE 26) ErrorCode GroupViewElement: :DisconnectA110 { ErrorCode err = SUCCESS ; err = FirstO ; while (lerr) { err = Disconnect ; if (lerr) err = Next0 ; } if (STATUS_NO_MORE_ROWS = err) { err = SUCCESS ; } return eπ ; } LISTING L44 ErrorCode GroupViewElement: :DeleteA110 { ErrorCode err = SUCCESS ; erτ = First0 ; while (lerr) { err = DeleteO ; if (lerr) err = Next0 ; } if (STATUS_NO_MORE_ROWS == err) { err = SUCCESS ; > return err ; } LISTING L45 * * GroupViewElement: :QueryO * ♦ Description: * Call Select to execute the query. * A non-null predicate will replace any current predicate. * For a top level query, pass fUseConnectPower as FALSE. ♦ For a query constrained by connection power, pass TRUE. * * Return Value: ♦ An ErrorCode indicating the result of the operation. */ ErrorCode GroupViewElement::Query( const char ♦ newPredicate, BOOL fUseConnectPower ) { ErrorCode err = SUCCESS; // Queries on x-tables are really done by the child table. if ( XJTABLE = role ) { err = XTableChildO->Query(newPredicate, fUseConnectPwr) ; return er ; } if ( NULL 1= newPredicate ) predicate = newPredicate ; //Now execute the Select for the parent row err = Select( TRUE, FALSE, fUseConnectPower) ; return err, > LISTING L46 /*+**+*+* **+****+* *****+*+*** Φ * * * Φ Φ LISTING L47 ErrorCode GroupViewElement: :Select( BOOL fExtendedRead, // Whether to read related tables BOOL fParentConstraint, //Bound to parent instance BOOL fUseConnectPower // Apply connection power ) { String predicate, commandStrin ; ViewElementListparamList ; TableRef tableRef( this ) ; // Define parent instance predicate; fetch for grid (Find) if ( fParentConstraint ) { ParentInstancePredicate( predicate ) ; } else { if ( fUseConnectPower ) { // Define connection power predicate; for embedded search predicate = ConnectPowerPredicateO ; } } // Search for local predicates in all group views DefinePredicateDσwn( predicate, fExtendedRead, tableRef) ; // Traverse the table reference tree to define SQL clauses // This is mainly done to differentiate INNER or OUTER joins String tableNames, colNames, whereClause ; tableRef.GatherJoin( colNames, tableNames, whereClause, FALSE ); // Put together a SQL SELECT commnad commandString = "SELECT " + colNames + " FROM " + tableNames + " WHERE " + predicate + " AND " + whereClause ; // Ready to execute the SELECT command err = ExecuteSQLString( commandString ) ; return err ; } LISTING L48 void GroupViewElement: :ParentInstancePredicate( String &predicates // Concatenate new predicate string ) const { String subquery, selectClause, parentPredicate ; ViewElement ♦ pFK = ForeignKey( parentTableGroup ) ; ViewElement *pFKTableGroup = pFK->ParentTableGroupO ; // The last parameter to ParamJoin indicates if foreign key or primary key // columns are to be compared (TRUE means test FK col against PK value) if ( pFKTableGroup == this ) // Foreign key is in this group view { /* * SELECT ♦ FROM g * WHERE g.fk=? ♦ / pFK->ParamJoin( parentPredicate, TRUE ) ; } else if ( pFKTableGroup->RoleO == XJTABLE ) { // Foreign key is in the parent intersection table /* ♦ SELECT * FROM so2 ♦ WHERE EXISTS(SELECT ♦ FROM x WHERE x.fkl=? AND so2.id_=x.fk2) ♦ / pFK = pFKTableGroup->ForeignKey( pFKTableGroup->ParentTableGroupO ) ; pFK->ParamJoin( parentPredicate, TRUE ) ; TableRef tableRef( pFKTableGroup ) ; SubQueryStr( subquery, " ♦M , tableRef, parentPredicate, this ) ; parentPredicate = "EXISTS ( " + subquery + ")" ; } else if ( pFKTableGroup = parentTableGroup ) { // Foreign key is in the (non-intersection) parent table /* * SELECT * FROM so2 ♦ WHERE so2.id_=7 ♦ / pFK->Para Join( parentPredicate, FALSE ) ; } LISTING L49 420 // Foreign keys are in a child group for multi-valued component, hybrid I 430 else 440 { 450 / ♦ 460 ♦ SELECT * FROM so2 470 * WHERE EXISTS( SELECT ♦ FROM gl 480 * WHERE so2.id_=gl.so2_fk 490 * EXISTS( SELECT * FROM g2 500 * WHERE gl.id_=g2.gl k AND g2.sol_fk=? ) ) 510 */ 520 pFK->ParamJoin( parentPredicate, TRUE ) ; 530 // Form subqueries until reaching the primary group 540 do { 550 TableRef tableRef( pFKTableGroup ) ; 560 tableRef.ColumnNames( selectClause, TRUE ) ; 570 SubQueryStr( subquery, selectClause, tableRef, parentPredicate ) ; 580 parentPredicate = "EXISTS(" + subquery + ')' ; 590 pFKTableGroup = pFKTableGroup->ParentTableGroupO ; 600 } 610 while ( FKTableGroup && ( pFKTableGroup 1= this )); 620 } 630 // Add the parent predicate to the output predicate string 640 predicates = parentPredicate ; 650 } LISTING L49 (continued) GroupViewElement: :ParamJoin( String &predicate, BOOL IFKValue // if TRUE, compare to FK value ) const { ViewElementlter iter = contents ; while φVE = iter++) { pVE->ParamJoinφredicate, fFKValue) ; } } LISTING L50 ViewElement: :ParamJoin( String &predicate, BOOL fFKValue // if TRUE, compare to FK value ) const { String join ; if(!predicate.IsEmptyO) join = " AND " ; ViewElement ♦ pColVE ; // column to compare ViewElement *p Value VE ; // value to compare // Assign view elements for the both side of a condition if (fFKValue ) { pColVE = this ; pValueVE = KeyPairO ; //FK = 7 } else { pColVE = KeyPairO ; // PK = ? pValueVE = this ; } // Construct a join condition join += pColVE->ParentTableGroupO->NameO + ". H + pColVE->NameO + " = "; join += pValueVE->StringValue( CURRENTJVALUE ) ; predicate += join ; } LISTING L51 S96/13284 -160- 10 String 20 GroupViewElement: :ConnectPowerPredicate const 30 { 40 String predicate ; 50 ViewElement *pFK = ForeignKeyφarentTableGroup) ; 60 ViewElement *pFKTable = pFK->ParentTableGroup0 ; 70 // Pre-define subquery for predicate when foreign key is in parent group. 80 String subquery ; 90 if ( pFKTable = parentTableGrou ) 100 110 TableRef tableRef( parentTableGroup ) ; 130 / STubQueryStr( subquery, "COUNT(*)", t /* -" "" ' 1 ^ βu,nιucιy ' - WJ UHTCT, taabblleeRReeff,, 1 NULL, this ) ; M0 ^ subquery - "SELECT COUNT(*) FROM sol WHERE sol.*2=so2.id " 160 } 170 switch ( ConnectPowerO ) 180 { 190 case ConnectPower:: AVAILABLE : 200 if ( 1 < PairMaxCardO ) 210 { 220 /* 230 * SELECT ♦ FROM so2 240 ♦ WHERE pairMaxCard 2 26500 * ♦ / ( SELECT COUNTS) FROM sol WHERE sol.fk2=so2.id_ ) 270 270 if (PairMaxCardO < Cardinality ::AH0) 80 { 90 char pairCardStr[16] ; 00 sprintfφairCardStr, "%lu", PairMaxCardO) ; 10 predicate = pairCardStr + " > ( " + subquery + " )" • 20 } 30 break ; 40 50 // When pair max cardinality =1, FREE and AVAILABLE are synonymous. LISTING L52 SUBSTTTUTE SHEET RULE 26 710 break; 720 } 730 return predicate ; 740 } LISTING L52 (continued) int ViewElement::SubQueryPredicate( String &predicate // Concatenate new predicate string ) const { TableRef tableRef( this ) ; String newPredicates ; // Find any predicate in this branch int numPreds ; numPreds = DefinePredicateDownφewPredicates, FALSE, tableRef) ; //Form a subquery if any predicate found if( numPreds > 0 ) { String subquery ; String selectClause ; TableRef tempRef( this ) ; tempRef.ColumnNames( selectClause, TRUE ) ; SubQueryStr( subquery, selectClause, tableRef, newPredicates, ParentTableGroupO ) ; if(lpredicateJsEmptyO) predicate += " AND" predicate += " EXISTS ( " + subquery + " )" ; } return( numPreds ); } LISTING L53 define sub-query finition list or this group e joined, may be NULL otherRef.InnerJoins( joins ) ; } subquery = "SELECT " + pSelectClause + " FROM " + fromClause + " WHERE " + pPredicates + " AND " + joins ; } LISTING L54 int GroupViewElement: :DefinePredicateDown( String &predicate, // Concatenate new predicate string BOOL fExtendedRead, // Whether to read related tables TableRef &tableRef // Specifies tables to be joined ) const { int numPreds = 0 ; // Number of predicates found ViewElement *pVE ; ViewElementlter iter = contents ; // Get iterator for view elements String newPred ; char *pAnd ; pAnd = predicateJsEmptyO 7 "" : " AND " ; // First add a predicate for this group element newPred = PredicateO ; if ( InewPredJsEmptyO ) { predicates += pAnd + newPred ; ++numPreds; pAnd = " AND " ; } // The current group may be an association group, get table group GroupViewElement *pTableGVE = ( IsTableO ) ? this : parentTableGroup ; // Iterate through member view elements while ( pVE = iter-H- ) { // Single-valued Simple value component; get predicate if ( pVE->IsColumnO ) { newPred = pVE->PredicateO ; if ( InewPredJsEmptyO) { predicate = pAnd + pTableGVE->NameO + '-' + pVE->Name0 + newPred ; ++numPreds; pAnd = " AND " ; } } else if ( !pVE->IsTable0 ) { // Single-valued group; get to its members numPreds += pVE->DefinePredicateDown( predicates, fExtendedRead, tableRef) ; } else LISTING L55 450 { 460 // Process table group depending on table relations 470 ViewElement *pFKGVE = pTableGVE->ForeignKey( pVE ); 480 ViewElement *pFKTblGVE = pFKGVE->ParentTableGroupO ; 490 ViewElement *pKeyPairGVE = pFKGVE->KeyPairO->ParentTabIeGroupO ; 500 //Object table in hybrid I; 510 // go up from multi-valued group containg a link 520 if (( pFKTblGVE != pTableGVE ) && ( pFKTblGVE != pVE )) 530 { 540 numPreds += pFKTblGVE->DefinePredicateUp(NULL, predicates, 550 fExtendedRead, tableRef) ; 560 > 570 // Object table in hybrid II; 580 // go up from multi-valued group containg a link 590 else if (φTableGVE->RoleO = XJTABLE) && φKeyPairGVE 1= pVE)) 600 { 610 numPreds += pKeyPairGVE->DefinePredicateUp(NULL, predicates, 620 fExtendedRead, tableRef) ; 630 > 640 // Process table group view element for one-to-many predicates 650 else if ( pVE->MaxCardO > 1 ) 660 { 670 numPreds += pVE->SubQueryPredicate( predicates ); 680 } 690 // Process table group view element for one-to-one predicates 700 else if ( pVE->MaxCardO == 1 ) // Single-valued object link 710 { 720 numPreds += pVE->JoinPredicateφredicates, fExtendedRead, tableRef) ; 730 } 740 } 750 } 760 return( numPreds ); 770 } LISTING L55 (continued) int GroupViewElement: :JoinPredicate( String &predicates, // Concatenate new predicate string BOOL fExtendedRead, // Whether to read related tables TableRef &tableRef // Specify table references ) const { TableRef *pNewTableRef = new TableRef( this, AtableRef ) ; int numPreds = DefinePredicateDownφredicates, fExtendedRead, *pNewTableRef ) ; // Force inner join if any predicate defined in this branch if( numPreds > 0 ) { pNewTableRef->JoinType( TableRef: :INNER ) ; } else if ( .'fExtendedRead ) { // No predicates, and not an extended read, so delete pNewTableRef delete pNewTableRef ; > return( numPreds ); } LISTING L56 int GroupViewElement: :DefinePredicateUp( ViewElement *pLastView, // Group view processed last String &predicates, // Concatenate new predicate string BOOL fExtendedRead, // Whether to read related tables TableRef AtableRef // Specifies tables to be joined ) const { int numPreds = 0 ; //Number of predicates found char *pAnd = predicateXsEmpryO 7 "" : " AND " ; TableRef *pNewTableRef = new TableRef( this, &tableRef ) ; pNewTableRef->JoinType( TableRef: :INNER ) ; //Force inner join // First add a predicate for this group element String newPred = PredicateO ; if ( InewPredJsEmptyO ) { predicates += pAnd + newPred ; -H-numPreds; } // Process member view element ViewElement *pVE ; ViewElementList nestedGroups ; ViewElementlter iter = contents ; LISTING L57 430 nestedGroups.AddTail( pVE ) ; 440 } 450 // Process table group view element except the one came up from 460 else if ( pLastView 1= pVE ) 470 { 480 BOOL fExRead = ( SOJTABLE = role ) ; 490 numPreds += pVE->DefinePredicateDown( predicates, 500 fExRead, *pNewTableRef ) ; 510 } 520 if ( iter. AtEndO && InestedGroupsJsEmptyO ) 530 { 540 iter = *(nestedGroups.RemoveHeadO) ; 550 } 560 } 570 // Move up the tree to the next parent table group if this is still ATTR table 580 if ( A TTRJTABLE == role ) 590 { 600 numPreds += ParentTableGroupO->DefinePredicateUp( this, predicates, 610 fExtendedRead, *pNewTableRef ) ; 620 } 630 // Table refs are not needed if no predicate found and extended read not specified 640 if ( InumPreds &.& IfExtendedRead ) 650 { 660 delete pNewTableRef ; 670 } 680 return( numPreds ); 690 } LISTING L57 (continued) class TableRef { public: enum Join { NONE, INNER, LEFTOUTER } ; TableRef( GroupViewElement *pGV, TableRef *pParent=NULL ); virtual -TableRefO; //Accessors BOOL IsEmptyO const ; //Has any table joins on this TableRef *ParentRe_0 const ; TableReflter ChildTablesO const ; GroupViewElement *GroupViewO const ; Join JoinTypeO const ; void JoinType( Join newType ) ; // For constructing select statements String &TableNames( String &tables ) const ; String &ColumnNames( String &columns, BOOL fPrimary=FALSE ) const ; String &InnerJoins( String &joinConditions ) const ; String &JoinCondition( String &joinConditions ) const ; void GatherJoin( String &colNames, String &tableNames, String &pkfkRelation, BOOL fUseOuter ) ; protected: // Internal construction tools void Attach( TableRef *pRef) ; void Detach( TableRef *pRef) ; // Data members GroupViewElement *pGroupView ; // Specify a table to operate on Join joinType ; // Join type to perform, NONE for primary table TableRef *pParentRef; //Parent TableRef attached to TableRefList tableRefList ; // Specify tables to be joined }; LISTING L58 TableRef::TableRef( GroupViewElement *pGVE, // To specify a table TableRef *pParent //Parent TableRef object to attach to ) : pGroupView( pGVE ), pParentRef( pParent ), joinType( ( IpParent || pGVE->MinCardO ) ? INNER : LEFTOUTER ) { if(pParentRef) { pParentRef->Attach( this ) ; } } LISTING L59 TableRef::~TableRefO { TableReflter reflter( tableRefList ) ; while ( Ireflter.AtEndO ) { ( refϊtei-H- )->TableNames( tables ) ; } return tables ; } LISTING L61 String & TableRef::ColumnNames( String ..columns, // Output String BOOL fPrimary // Whether to limit to the primary key ) const { ViewElementlter velter ; char *comma = columns sEmptyO 7 "" : \ " ; ViewElement *pVE ; if (fPrimary ) { pVE = pGroupView->PrimaryKeyO ; ifφVE->IsGroupO) velter = pVE->Contents0 ; } else // All member elements { velter = pGroupView->ContentsO; } if(lpVE) pVE = velter++ ; // Now iterate the new list to find column names; do { columns += comma + pVE->ParentTableGroupO- NameO + "•" + pVE->Name0 ; comma = ", " ; > while ( pVE = velter++ ) // Get all column names from child tableRefs TableReflter reflter( tableRefList ) ; while ( Ireflter.AtEndO ) { ( reflter-H- )->ColumnNames( columns ) ; } return( columns ); } LISTING L62 String & TableRef::InnerJoins( String &join // Output inner join conditions ) const { TableRef *pRef; TableReflter reflter( tableRefList ) ; while ( pRef = reflter-H- ) { pRef->JoinCondition( join ) ; //To this parent pRef->InnerJoins( join ) ; // From the child tables } return join ; } LISTING L63 String & TableRef: :JoinCondition( String &join // Output inner join conditions ) const { if(pParentRef) { ViewElement *pVE ; ViewElement *pKeyPair ; ViewElementlter velter ; pVE = pGroupView->ForeignKey( pParentRef->pGroupView ) velter = pVE->Contents0 ; char *pAnd = "" ; pVE = veIter++ ; do { pKeyPair = pVE->KeyPai_0 ; join += pAnd + pVE->ParentTableGroupO->NameO + "." + pVE->Name0 + " = " + ρKeyPair->ParentTableGroupO->NameO + "•" + pKeyPair->NameO; pAnd = " AND " ; } while ( pVE = velter++ ) } return join ; } LISTING L64 void TableRef: :GatherJoin( String &colNames, // Gathers together Column names to Bind String &tableNames, // Gathers together table names and OJ links String &pk_kRelation, // Add pk/fk relation of inner joined childem BOOL fUseOuter // An Outer Join has occurred in the recursion ) { String join ; JoinCondition( join ) ; char *comma = tableNamesJsEmpryO ? "" : ", " ; // Need to outer join if this table is defined as or forced to OUTER JOIN if ( fUseOuter || ( JoinTypeO = TableRef: :LEFTOUTER ) ) { tableNames += " LEFT JOIN " + GroupView0->Name0 + " ON " +join ; // Further join are to use OUTER fUseOuter = TRUE ; } else { tableNames += comma + Group View0- Name0 ; if(!pk_kRelation.IsEmptyO) pkfkRelation += " AND " ; pkfkRelation += join ; } // Define columns for select and find all columns to bind ViewElement *pVE ; ViewElementlter velter = GroupView0->Contents0 ; String tblName = GroupView0->Name0 + "•" ; Group ViewElementList nestedGroups ; comma = colNamesJsEmpty0 1 ' LISTING L65 330 while ( pVE = velterH- ) 340 { 350 if ( pVE->IsColumnO ) 360 { 370 colNames += comma + tblName + pVE->NameO ; 380 comma = ", " ; 390 } 400 else if ( pVE->IsGroupO && Ip VE->IsTableO ) 410 { 420 nestedGroups += pVE ; 430 } 440 if ( velter. AtEndO && InestedGrσupsJsEmptyO ) 450 { 460 velter = *(nestedGroups.RemoveHeadO) ; 470 } 480 } 490 // Iterate thru each of the child ref trees 500 TableRef *childRef; 510 TableReflter trlter = ChildTablesO ; 520 while ( NULL != ( childRef = trlter++) ) 530 { 540 // Append the new joins; nest outer joins if this was outer joined. 550 childRef->GatherJoin( colNames, tableNames, pkfkRelation, fUseOuter ); 560 } 570 } LISTING L65 (continued) ErrorCode GroupViewElement: :DoDatabaseUpdateO { String sqlCommand ; ErrorCode err ; sqlCommand = "UPDATE " + NameO + " SET " ; sqlCommand += FindColumns( UpdateColumnValues, ", " ) ; sqlCommand += " WHERE " ; sqlCommand += FindColumns( WherePredicate, " AND " ) ; err - ExecuteSQLString( sqlCommand ) ; return err ; } LISTING L66 ErrorCode GroupViewElement: :DoDatabaseDeleteO { String sqlCommand ; ErrorCode err ; sqlCommand - "DELETE FROM " + NameO + " WHERE " ; sqlCommand += FindColumns( WherePredicate, " AND " ) ; err = ExecuteSQLString( sqlCommand ) ; return err ; } LISTING L67 String GroupViewElement: :FindColumns( String (*pPredicateFunc)(ViewElement *pVE), const char *colSep ) { Group ViewElementList nestedGroups ; ViewElementlter iter = contents ; ViewElement *pVE ; String answer, piece ; while φVE = iter++) { ifφVE->IsColumnO) { piece = (*pPredicateFunc)φVE) ; if(lpieceJsEmptyO) { if (lanswerJsEmptyO) answer += colSep ; answer += piece ; } } else if (lpVE->IsTableO) { nestedGroups += pVE ; } if (velter. AtEndO && InestedGroupsJsE ptyO) { GroupViewElement *pGVE = nestedGroups.RemoveHeadO ; iter = pGVE->ContentsO ; } } return answer ; } LISTING L68 String UρdateColumnValues( ViewElement *pVE ) { String retStrin ; if ( pVE->IsUpdatedO ) { retString = " " + pVE->NameO + " = " ; retString += pVE->StringValue( CURRENTJVALUE ) ; return retString ; } LISTING L69 String WherePredicate( ViewElement *pVE ) { String retString ; if ( lφVE->DBDataTypeO — ViewElement: :DBT LONGVARCHAR II pVE->DBDataTypeO — ViewElement: rDBTJLONGVARBINARY) ) retString = " ; retString += pVE->NameO ; if ( ( ppVVEE-->>IIssNNuullll(( O ORRIIGGIINNAA1L VALUE ) ) { - j ) tString += " IS NULL" ; retString += " = « ; retString += pVE->StringValue( ORIGINALJVALUE ) ; return retString • } LISTING L70 SUBSTTTUTE SHEET (RULE 26) ErrorCode GroupViewElement: :DoDatabaseInsertO { String sqlCommand ; ErrorCode err ; sqlCommand = "INSERT INTO " + NameO + "(" ; sqlCommand += FindColumns( InsertColumns, ", " ) ; sqlCommand += ") VALUES (" ; sqlCommand +== FindColumns( InsertValues, ", " ) ; sqlCommand += ")" ; err = ExecuteSQLString( sqlCommand ) ; return err ; } LISTING L71 LISTING L72 String InsertValues( RTViewElement *pVE ) { return pVE->StringValue( CURRENTJVALUE ) ; } LISTING L73 CREATE TABLE CUSTOMER( CREATE UNIQUE INDEX IDX650 ON CUSTOMER(COMPANY_NAME) CREATE TABLE CUSTOMER_CUSTOMER_CONTACTS( CUSTOMER DJFK INTEGER NOT NULL, CONTACT_NAME VARCHAR(10), DIRECT_LΪNE_AREA_CODE VARCHAR(3), DIRECT_LINEJPHONE_NUMBER VARCHAR(7), DIRECT_L_NE_EXTENSION VARCHAR(IO), ID_ INTEGER NOT NULL, PRIMARY KEY(ID_), FOREIGN KEY(CUSTOMER_ID_FK) REFERENCES CUSTOMER(ID J ON UPDATE CASCADE ) CREATE INDEX IDX663 ON CUSTOMER_CUSTOMER_CONTACTS(CONTACTJNAME) CREATE TABLE STOMER_CONTACTS_IMPORTANT_DATES( USTOMER_CUSTOMER_CONTACTS_fb_FK INTEGER NOT NULL, EVENT VARCHAR(IO), EVENT_DATE DATE, ID_ INTEGER NOT NULL, PRIMARY KEY(IDJ, FOREIGN KEY(USTOMER_CUSTOMER_CONTACTS_IDJFK) REFERENCES CUSTOMER_CUSTOMER_CONTACTS(ID J ON UPDATE CASCADE ) LISTING L74 360 CREATE TABLE ORDER_KW( 440 PRIMARY KEYtJDJ, 450 FOREIGN KEY(CUSTOMER D_FK) 460 REFERENCES CUSTOMER(_D ON UPDATE CASCADE 470 ) 480 CREATE UNIQUE INDEX IDX673 ON ORDER_KW(ORDER_NUMBER) 490 CREATE TABLE ITEM( 600 CREATE INDEX IDX684 ON TTEM(PRODUCT_NAME) 610 CREATE UNIQUE INDEX IDX686 ON _TEM(PRODUCTJNUMBER) 620 CREATE TABLE ORDER_LINE_ITEM( INTEGER NOT NULL, INTEGER NOT NULL, NUMERIC(15, 4), SMALLINT, VARCHAR(10), INTEGER NOT NULL, 690 PRIMARY KEYt DJ, 700 FOREIGN KEY(ORDER_ID_FK) 710 REFERENCES ORDER_KW(_DJ ON UPDATE CASCADE, 720 FOREIGN __EY(ITEMJD_FK) 730 REFERENCES __EM(_D ON UPDATE CASCADE 740 ) LISTING L74 (continued) 750 CREATE TABLE SUPPLIER( 760 COMPANY NAME VARCHAR(35) NOT NULL, 770 ADDRESS_STREET VARCHAR(30), 780 ADDRESS CITY VARCHAR(20), 790 ADDRESS~STATE VARCHAR(2), 800 ADDRESS JZIP VARCHAR(9), 810 PHONE AREA_CODE VARCHAR(3), 820 PHONE_PHONE_NUMBER VARCHAR(7), 830 FAX_AREA_CODE VARCHAR(3), 840 FAX_PHONE_NUMBER VARCHAR(7), 850 PAYMENT TERMS VARCHAR(10), 860 SU_TLffiR_RA__NG VARCHAR(10), 870 COMMENTS MEMO, 880 ID_ INTEGER NOT NULL, 890 PRIMARY KEY(IDJ 900 ) 910 CREATE UNIQUE INDEX IDX695 ON SUPPLIER(COMPANY_NAME) 920 CREATE TABLE SUPPLIER_SUPPL_ER_CONTACTS( 930 SUPPLIER IDJFK INTEGER NOT NULL, 940 CONTACT " NAME VARCHAR(IO), 950 DIRECT_L_NE_AREA_CODE VARCHAR(3), 960 D_RECTJLINE_PHONE_NUMBER VARCHAR(7), 970 DIRECT_LINE_EXTENSION VARCHAR(10), 980 ID_ INTEGER NOT NULL, 990 PRIMARY KEYflD , 1000 FOREIGN __EY(SUPPLIER_ID_FK) 1010 REFERENCES SUPPLIER(ID J ON UPDATE CASCADE 1020 ) 1030 CREATE INDEX IDX697 ON SUPPLffiR_SUPPLffiR_CONTACTS(CONTACT_NAME) 1040 CREATE TABLE SUPPLIERJTEMJX( 1050 SUPPLIERJDJFK INTEGER NOT NULL, 1060 ΓΓEM_ID_FK INTEGER NOT NULL, 1070 PRIMARY KEY(SUPPL_ER_ID_FK, _TEM_ID_FK), 1080 FOREIGN KEY(SUPPL_ER_ID_FK) 1090 REFERENCES SUPPLIER(ID J ON UPDATE CASCADE, 1100 FOREIGN KEY(TrEM_ID_FK) 1110 REFERENCES TTEM(_b J ON UPDATE CASCADE 1120 ) LISTING L74 (continued) 1130 CREATE TABLE S___PPING_COMPANY( 1230 CREATE UNIQUE INDEX IDX716 ON SHIPPING_COMPANY(SH_PP_NG_COMPANY) 1240 CREATE TABLE MPANY_SffiPPING COMPANY CONTACTS( 1250 SH_PPING_COMPANY_ID_FK INTEGER NOT NULL, 1260 CONTAC NAME VARCHAR(10), 1270 DIRECT LINE_AREA_CODE VARCHAR(3), 1280 DIRECT~LINE_PHONijNUMBER VARCHAR(7), 1290 DIRECT_LINE_EXTENSION VARCHAR(10), 1300 ID_ INTEGER NOT NULL, 1310 PRIMARY KEY(ID_), 1320 FOREIGN KEY(SHIPPING COMPANY_ID FK) 1330 REFERENCES SfflPPING_COMPANY(ID J ON UPDATE CASCADE 1340 ) 1350 CREATE INDEX IDX724 ON 1360 MPANY_SH_PPING_COMPANY_CONTACTS(CONTACTJNAME) 1370 CREATE TABLE SHIPPING COMPANY SHIPMENT( 1380 S_flFPING_COMPANY_ID_FK INTEGER NOT NULL, 1390 DATEJSHIPPED DATE, 1400 DATE_RECEIVED DATE, 1410 RECEIVED_BY VARCHAR(20), 1420 PACKING SLIP NUMBER . VARCHAR(10) NOT NULL, 1430 ID_ INTEGER NOT NULL, 1440 PRIMARY KEY(_DJ, 1450 FOREIGN KEY(SHIPPING_COMPANY_ID_FK) 1460 REFERENCES SHIPPING COMPANY(ID J ON UPDATE CASCADE 1470 ) 1480 CREATE UNIQUE INDEX IDX734 ON 1490 SHIPP G_COMPANY_S__IPMENT(PACKING_SLIP_NUMBER, 1500 SH_PPING_COMPANY_ID_FK) LISTING L74 (continued) 1510 CREATE TABLE SHIPPING COMPANY_SHIPMENT ITEM( 1520 ΓΓEMIJD FK INTEGER NOT NULL, 1530 SHIPPING ?OMPA_ Y_S___PMENTJDJFK INTEGER NOT NULL, 1540 PRIMARY KEY(_TEM1_ID FK, SHIPPING COMPANY_S_FLPMENTJD_FK), 1550 FOREIGN KEY(SH_PPING " COMPANY SFFLPMENT_ID FK) 1560 REFERENCES SHIPPING C0MPANY_SHIPMENT(_D J~ON UPDATE CASCADE, 1570 FOREIGN KEY(TTEM1_ID_FK) 1580 REFERENCES ITEM(_D J ON UPDATE CASCADE 1590 ) LISTING L74 (continued)

Claims: The embodiments of the invention in which an exclusive property or privilege is claimed are defined as follows: 1. A method of storing data in a relational database using an object model, the object model including a plurality of objects, each object having one or more components that define the object, including relationships the object has, if any, with other objects in the object model, and wherein the object model has been translated into a database schema, including one or more relational database tables, that describes the relational database, comprising: (a) selecting an object from the object model; (b) automatically generating, according to a set of default rules, a form based on the selected object for storing data in the relational database; (c) combining the form with information about the database schema and information about the selected object, including information regarding any relationships that exist between the selected object and other objects in the object model; (d) prompting a user to enter data to be stored in the relational database into the form; and (e) writing the data that has been entered into the form to the relational database. 2. The method of Claim 1, wherein the objects in the object model are semantic objects. 3. The method of Claim 1, further including repeating steps (a)-(c) for each object in the object model. 4. The method of Claim 1, wherein the object in the object model for which a form is generated is selected in response to user input. 5. A computer-readable memory that can be used to direct a computer to function in the manner specified in Claim 1 when used by a computer. 6. The method of Claim 1, wherein the step of writing the data that has been entered into the form to the relational database includes: (a) determining if data entered into the form comprises a valid record in accordance with the object model; and (b) if the data that has been entered is not a valid record, displaying an error message without writing the data that has been entered into the form to the relational database. 7. The method of Claim 1, wherein the form is comprised of a collection of fields, each field being associated with either a component in the selected object or a component from an object that has a relationship with the selected object. 8. The method of Claim 7, wherein the fields comprising the form are determined by the set of default rules. 9. The method of Claim 8, further including enabling a user to change the fields contained in the form from those included by the default rules. 10. The method of Claim 1, further including enabling a user to modify the contents of the form from what is dictated by the default rules. 11. The method of Claim 1, wherein the step of automatically generating a form for storing data in the relational database includes: (a) automatically generating, according to a set of default rules, an object view hierarchy based on the semantic object, the object view hierarchy including information about the components defining the selected object as well as information regarding the relationships, if any, that exist between the selected object and other objects in the object model; and (b) using the object view hierarchy to generate the form. 12. The method of Claim 11, further including enabling a user to modify the contents of the form. 13. The method of Claim 12, wherein the step of enabling a user to modify the contents of the form includes: (a) displaying the form; (b) monitoring user inputs relating to the form to determine if the user has made any modifications to the contents of the form, and if modifications have been made, changing the contents of the object view hierarchy associated with the form to reflect the modifications; and (c) automatically generating a new form from the object view hierarchy. 14. The method of Claim 1, further comprising enabling a user to perform queries on data stored in the database using the form. 15. The method of Claim 1, wherein the form includes a plurality of fields, wherein each field is associated with a component in the object model. 16. The method of Claim 15, further comprising enabling a user to perform queries on data stored in the database using the form, including: (a) prompting a user to enter query information into one or more fields of the form; and (b) retrieving data records, if any, that match the query information and displaying those data records. 17. The method of Claim 16, wherein the step of retrieving data records includes generating a report of the data records, if any, that matched the query information. 18. The method of Claim 1, wherein the step of writing the data that has been entered into the form to the relational database includes generating SQL statements appropriate for the database from the information about the database schema and information about the selected object. 19. The method of Claim 1, wherein the step of combining the form with information about the database schema and information about the selected object includes creating a run-time view hierarchy for the form. 20. The method of Claim 1, wherein each component represents an instance of data stored in a relational database table that is represented by the object with which the component is associated, the components including simple value components that represent data entry in a single column of the relational database, group components having one or more member components that represent a logical collection of components, and object link components that represent relationships between the objects in the object model. 21. The method of Claim 20, wherein one or more components are classified as identifier components that are used to choose between instances represented by the same object, and each component has a minimum and maximum cardinality that define the minimum and maximum number of instances, respectively, allowed for the component. 22. The method of Claim 21, wherein the set of default rules includes adding to the form a control for each simple value component and each group component that defines the selected object, and a control for each identifier component in an object related to the selected object by a nonrecursive object link component. 23. The method of Claim 1, wherein an object in the object model contains one or more action components, each action component resulting in a command button being created on a form generated for the object. 24. The method of Claim 23, wherein an action component enables one the following functions to be invoked by a user of the form: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for a semantic object that is related to the semantic object that contains the action component. 25. The method of Claim 1, wherein an object in the object model contains an action group component, consisting of one or more action components, that results in a menu bar being created on a form generated for the object. 26. The method of Claim 25, wherein an action component in the action group component consists of one the following functions: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for an object that is related to the object defined by the action component. 27. The method of Claim 26, wherein the action group component contained by an object is used to limit access to data in the relational database by a user of a form associated with the object by providing only selected functions on the menu bar created on the form. 28. A method of storing and retrieving data to and from a relational database using an object model, comprising: (a) creating, in response to user input, an object model comprising one or more objects, each of which represents an item about which data is stored in one or more tables of a relational database; (b) creating, in response to user input, one or more components associated with one or more objects in the object model and representing data stored in the relational database for the item represented by the object with which the component is associated, the components including object link components that represent relationships between objects in the object model; (c) translating the object model into a database schema, including one or more relational database tables that describe the relational database; (d) automatically generating, in accordance with a set of default rules, an object view hierarchy for each object in the object model, each object view hierarchy containing information about its associated object, including the component or components defining the object and the object links, if any, between the associated object and other objects in the model; (e) automatically generating, in accordance with a set of default rules, a run-time view hierarchy for each object in the object model by combining information contained in an object's object view hierarchy with information in the database schema; and (f) automatically generating a form from each run-time view hierarchy that may be used to store and retrieve data to and from the relational database. 29. A computer-readable memory that can be used to direct a computer to function in the manner specified in Claim 28 when used by a computer. 30. The method of Claim 28, further including: (a) prompting a user to enter data to be stored in the relational database into a form; and (b) writing the data that has been entered into the form to the relational database. 31. The method of Claim 28, further including. (a) displaying, in response to user input, a current form that is of interest to the user; (b) prompting the user to enter modifications to the contents of the form; and (c) if modifications have been made to the current form by the user, changing the contents of the object and run-time view hierarchies associated with the form to reflect the modifications, and generating a modified form from the run-time view hierarchy. 32. A method of retrieving data records stored in a relational database using an object model, the object model including a plurality of objects, each object having one or more components that define the object, and wherein two or more of the objects are further defined by relationships therebetween, comprising: (a) automatically generating, according to a set of default rules, a form based on an object in the object model, the form including a plurality of fields, wherein each field is associated with a component in the object model; (b) prompting a user to enter query information into one or more fields of the form; and (c) retrieving data records, if any, that match the query information and displaying those data records. 33. A computer-readable memory that can be used to direct a computer to function in the manner specified in Claim 32 when used by a computer. 34. The method of Claim 32, wherein the step of retrieving data records includes the step of combining information about the database schema with information about the selected object, including information regarding any relationships that exist between the semantic object and other objects in the object model and using this information to perform the query on the relational database. 35. The method of Claim 32, wherein the step of retrieving data records includes generating a report of the data records, if any, that were located in the query. 36. The method of Claim 32, wherein one or more components representing the selected object is an action component that results in a command button being created on the form. 37. The method of Claim 32, wherein one or more components representing the selected object is an action group component that results in a menu bar being created on the form. 38. The method of Claim 32, wherein the step of retrieving data records includes generating SQL statements appropriate for the database from the information about the database schema and information about the selected object. 39. The method of Claim 32, wherein the step of automatically generating, according to a set of default rules, a form based on an object in the object model is repeated for each object in the object model. 40. A method of storing data in a relational database using an object model, the object model including a plurality of objects, each object having one or more components that define the object, including relationships the object has, if any, with other objects in the object model, and wherein the object model has been translated into a database schema including one or more relational database tables that describe the relational database, comprising: (a) selecting an object from the object model; (b) automatically generating, according to a set of default rules, an object view hierarchy based on the selected semantic object, the object view hierarchy including information about the components defining the selected semantic object as well as information regarding the relationships, if any, that exist between the selected semantic object and other semantic objects in the object model; (c) automatically generating a form for storing data in the relational database from the object view hierarchy; (d) prompting a user to enter information into the form; and (e) storing data that has been entered into the form into the relational database by combining information about the database schema with information contained in the object view hierarchy. 41. The method of Claim 40, further comprising repeating steps (a)-(c) for each semantic object in the object model. 42. A computer-readable memory that can be used to direct a computer to function in the manner specified in Claim 40 when used by a computer. 43. A method of creating forms based on a semantic object in a semantic object model that may be used to access a relational database stemming from the object model, comprising: (a) creating, in response to user input, an object model, the object model including a plurality of semantic objects, each semantic object having one or more components that define the semantic object, and wherein two or more of the semantic objects are further defined by relationships therebetween; (b) automatically generating, in accordance with a set of default rules, one or more object view hierarchies for each semantic object in the object model, the object view hierarchies containing information about an associated semantic object, including the component or components defining the corresponding semantic object and relationships with other semantic objects in the model, if present; (c) generating a form from each object view hierarchy; (d) displaying, in response to user input, a current form that is of interest to the user; and (e) determining if modifications have been made by the user to either the current form or the underlying object view hierarchy upon which it is based, and if modifications have been made, changing the contents of the underlying object view hierarchy or the current form, respectively, to reflect the modifications. 44. A computer-readable memory that can be used to direct a computer to function in the manner specified in Claim 43 when used by a computer. 45. The method of Claim 43, further comprising enabling a user to store data in the relational database using a form. 46. The method of Claim 43, wherein one or more components representing the selected object is an action component that results in a command button being created on a form associated with the object. 47. The method of Claim 43, wherein one or more components representing the selected object is an action group component that results in a menu bar being created on a form associated with the object. 48. The method of Claim 43, further comprising: (a) translating the object model into a database schema including one or more relational database tables that describe the relational database; (b) selecting, in response to user input, a form; (c) combining information about the database schema with information about the form contained in the object view hierarchy upon which the form is based; (e) prompting a user to enter data to be stored in the relational database into the form; and (f) writing the data that has been entered into the form to the relational database using the combined information about the database schema and the form. 49. The method of Claim 43, wherein a semantic object in the object model contains one or more action components, each action component resulting in a command button being created on a form generated from an object view hierarchy associated with the semantic object. 50. The method of Claim 48, wherein an action component enables one the following functions to be invoked by a user of a form: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for a semantic object that is related to the semantic object that contains the action component. 51. The method of Claim 43, wherein a semantic object in the object model contains an action group component, consisting of one or more action components, that results in a menu bar being created on a form generated from an object view hierarchy associated with the semantic object. 52. The method of Claim 51, wherein an action component in the action group component consists of one the following functions: reading a record stored in the relational database; inserting a record into the relational database; deleting a record from the relational database; updating a record stored in the relational database; and showing a form for a semantic object that is related to the semantic object defined by the action component. 53. The method of Claim 52, wherein the action group component contained by a semantic object is used to limit access to data in the relational database by a user of a form associated with the semantic object by providing only selected functions on the menu bar created on the form. 54. A database management system for storing data in a relational database using an object model, the database management system including a processor and memory coupled to the processor, each object having one or more components that define the object, including relationships the object has, if any, with other objects in the object model, and wherein the object model has been translated into a database schema including one or more relational database tables that describe the relational database, comprising: (a) means for selecting an object from the object model; (b) means for generating, according to a set of default rules, a form based on the selected object for storing data in the relational database; (c) means for combining the form with information about the database schema and information about the selected object, including information regarding any relationships that exist between the selected object and other objects in the object model; (d) means for prompting a user to enter data to be stored in the relational database into the form; and (e) means for writing the data that has been entered into the form to the relational database. 55. The system of Claim 54, wherein the objects in the object model are semantic objects. 56. The system of Claim 54, wherein the object in the object model for which a form is generated is selected in response to user input. 57. The system of Claim 54, wherein a form is generated for each object in the object model. 58. The system of Claim 54, wherein the means for writing the data that has been entered into the form to the relational database includes: (a) means for determining if data entered into the form comprises a valid record in accordance with the object model; and (b) if the data that has been entered is not a valid record, displaying an error message without writing the data that has been entered into the form to the relational database. 59. The system of Claim 54, wherein the form is comprised of a collection of fields, each field being associated with either a component in the selected object or a component from an object that has a relationship with the selected object. 60. The system of Claim 59, wherein the fields comprising the form are determined by the set of default rules. 61. The system of Claim 60, further including means for enabling a user to change the fields contained in the form from those included by the default rules. 62. The system of Claim 61, further including means for enabling a user to modify the contents of the form from what is dictated by the default rules. 63. The system of Claim 54, wherein the means for generating a form for storing data in the relational database includes: (a) means for generating, according to a set of default rules, an object view hierarchy based on the semantic object, the object view hierarchy including information about the components defining the selected object as well as information regarding the relationships, if any, that exist between the selected object and other objects in the object model; and (b) means for generating the form from the object view hierarchy. 64. The system of Claim 63, further including means for enabling a user to modify the contents of the form. 65. The system of Claim 64, wherein the step of enabling a user to modify the contents of the form includes: (a) means for displaying the form; (b) means for monitoring user inputs relating to the form to determine if the user has made any modifications to the contents of the form, and if modifications have been made, changing the contents of the object view hierarchy associated with the form to reflect the modifications; and (c) means for generating a new form from the object view hierarchy. 66. The system of Claim 54, further comprising means for enabling a user to perform queries on data stored in the database using the form. 67. The system of Claim 54, wherein the form includes a plurality of fields, wherein each field is associated with a component in the object model. 68. The system of Claim 54, wherein the means for writing the data that has been entered into the form to the relational database includes means for generating SQL statements appropriate for the database from the information about the database schema and information about the selected object. 69. The system of Claim 54, wherein the means for combining the form with information about the database schema and information about the selected object includes means for creating a run-time view hierarchy for the form. 70. The system of Claim 54, wherein each component represents an instance of data stored in a relational database table that is represented by the object with which the component is associated, the components including simple value components that represent data entry in a single column of the relational database, group components having one or more member components that represent a logical collection of components, and object link components that represent relationships between the objects in the object model. 71. The system of Claim 54, wherein one or more components are classified as identifier components that are used to choose between instances represented by the same object, and each component has a minimum and maximum cardinality that define the minimum and maximum number of instances, respectively, allowed for the component. 72. The system of Claim 71, wherein the set of default rules includes adding to the form a control for each simple value component and each group component that defines the selected object, and a control for each identifier component in an object related to the selected object by a nonrecursive object link component.

Inventors: CAI ZHIYA, GORDON MATTHEW C, KAWAI KENJI, KROENKE DAVID M, LI JING, MILLER MICHAEL D, OLDS CHRISTOPHER C, STANFORD CATHRYN A, CAI, ZHIYA, GORDON, MATTHEW, C., KAWAI, KENJI, KROENKE, DAVID, M., LI, JING, MILLER, MICHAEL, D., OLDS, CHRISTOPHER, C., STANFORD, CATHRYN, A.
Applicants: WALL DATA INC, WALL DATA INCORPORATED
Application year: 1996
Main classification: G06F17
IPC codes: G06F17