Oracle Power Objects provides a data-centric approach to application development; the evidence is in the tight integration between the Form Designer and the supported database back ends. You can construct forms using the familiar drag-and-drop metaphor.
Application-enforced referential integrity and transaction processing are also tightly integrated into the automated design environment. This chapter discusses these areas of application development using the Form Designer.
In Power Objects, you construct applications with forms, reports, bitmaps, classes, and OLE objects. Building a simple data entry form is as easy as picking the columns from a table, dragging and dropping them onto a form, and then running the form.
Using the CONTACT table from the SAMPLE session and the TakeNote application, both from the Oracle Power Objects 1.0 samples, look at how easy it is to create a simple data entry form in the Microsoft Windows environment.
A developer needs an application with a form and a session connecting to a database in order to build a data entry form. The following steps guide you through this simple procedure.
- Create an application named UNTITLED.POA.
- Create a form and set its name property to CONTACT.
- Open the SAMPLE session and connect to the Blaze database by double-clicking on the session icon.
- Open the CONTACT table by double-clicking its icon in the SAMPLE database session window.
- Using the Ctrl key and the mouse, select the columns indicated in the Figure 41.1 from the CONTACT table.
- After selecting the columns, click and hold down the mouse on one of the columns selected. While holding down the mouse, drag the columns onto the CONTACT form. The cursor changes to a document icon.
- Releasing the mouse over the CONTACT form creates the labels and fields shown in Figure 41.1.
Figure 41.1. Drag-and-drop form
You can run this form or reposition fields as you like. The down side to running the CONTACT form at this point is that you can only view the first record in the table. You do not have a method for scrolling through records.
Adding scrolling to a form is just one example of how Power Objects is a data-centric development tool. In Visual Basic, a scroll bar can scroll data only through extensive coding. In Power Objects, the scroll bar automatically scrolls through a record
set when you set the ScrollObj property. The ScrollObj property is set automatically when you place the scroll bar object on a form or manually when the developer types a value into the ScrollObj property.
Figure 41.2 shows the horizontal scroll bar object selected from the tool palette. I placed the scroll bar onto the form named CONTACT, and the ScrollObj property was filled in automatically with the value container, which is an object identifier.
container is an indirect object reference to the object containing the scroll bar.
Figure 41.2. Scrolling through
At this point, the CONTACT form is ready to test. Power Objects is equipped with a design-time test environment where a developer can test a specific form or an entire application. If the developer wants to, he can also turn on the Power Objects
debugger. Because you do not expect any problems to exist at this point, simply run the form by clicking the RunForm icon on the toolbar.
Figure 41.3 shows the running form. You display the first and second records by clicking the right arrow on the scroll bar.
Figure 41.3. Running a
Creating master-detail relationships is one of the many strengths of Power Objects. If you drag and drop columns from the CONTACT table onto a form and give that form a scrolling capability, that form can serve as a master object. You can create a
repeater object on the form and drag and drop columns from the TASKS table onto it. This would be a separate master object at this point. To make it the detail object, simply type in the values for three properties. The LinkDetailColumn
and LinkMasterColumn properties are the database column names that form a "join" relationship between the master and detail objects. Because you set these property values on the detail form or object, you must specify what the
master form or object is in the LinkMasterForm property. Figure 41.4 illustrates what is involved.
Figure 41.4. Design-time master-detail relationships.
At this point, you could run the form, and you'd see that the detail data scrolls as the master data changes. The master-detail relationship has been established. Figure 41.5 displays this successful relationship.
Figure 41.5. Run-time master-detail
A common problem for PowerSoft's PowerBuilder is when two or more data controls want to share the same data source; for example, they each want to manipulate values for a given record and maintain data synchronization between the various controls. Power
Objects took care of this shortcoming in PowerBuilder by permitting the "sharing" of record sources. For example, you might want a master list of contacts displaying only names and a separate detail section displaying some specifics on the
contact. You want to be able to edit the name in either location and have the changes reflected and posted to the database properly. Power Objects built this functionality into the product so that you don't have to add it through coding. Figure 41.6
illustrates this "shared" record source concept.
Figure 41.6. A shared record source.
As the user scrolls through the records in the master list, the detail section updates to show a different view of the same record. Changes made in the master list are also made in the detail section. Figure 41.7 demonstrates the synchronization without
any additional coding.
Figure 41.7. Synchronizing data through a shared record
Supporting Business Rules with Application-Enforced Constraints
Although database-enforced constraints support business rules and data integrity uniformly on the back end, it is also possible to ensure data integrity with Oracle Basic method code in methods such as PreInsert() and PreUpdate() (refer to the
validation-related topics later in this chapter for more on these methods). However, such business rules or application constraints are associated with the object containing the method and not the database object itself, so they are more difficult
to support and maintain. You can reduce the maintenance and support burden by using user-defined methods for common business rule modelssuch as a user value must be between two specified values. A user-defined method could be defined as
function IsBetween( testValue, lower, upper ) as Boolean, which returns TRUE or FALSE as appropriate.
It is a good business practice to enforce business rules on the database server back end whenever possible. The advantage here is that the application developer might forget to encode application constraints everywhere they are needed, but the database
applies the same constraint to a given transaction no matter where in the application it was generated. Power Objects is innovative in that it provides for application-enforced constraints so that the developer could use a database backend server, such as
dBASE, that does not have the capability to enforce constraints. Another good business practice is to encode business rules in the application layer when you consider a database back end that might not support constraints.
As the user enters a new value into a control, you can enforce business rules using the Validate() method and the ValidationMsg property. By entering the necessary code in the Validate() method for the control, you can set the business rule to be
enforced whenever the user changes the value of the control.
As a result, you can prevent the user from entering negative values into a control by having the Validate() method return FALSE whenever it detects an internal value for the control that is less than zero. If you have entered text in the ValidationMsg
property of the control, that text appears in a warning dialog box when the validation fails.
When Validate returns FALSE, the internal value of the control remains set to its original value, but the display value remains unchanged. The user can still see the mistaken value entered for the control, making it possible to enter changes without
completely retyping the value. If you want the display value to automatically revert to the original value of the control, call the RevertValue() method from within the Validate() method. Figure 41.8 illustrates a Validate() method that ensures the user
enters a value in the range from $0.01 to $100,000.00.
Figure 41.8. Range check validation on a field.
Validate() is useful when checking the value entered into a single control. When you want to check values entered in several controls, use the ValidateRow() method. ValidateRow() is triggered whenever the user tries to save changes to an existing
record. As a result, ValidateRow() is especially useful when checking on dependencies among the values appearing in multiple controls.
The ValidateRow() method appears on a container, not on an individual control. When ValidateRow() returns FALSE, the application displays any text entered for the ValidateRowMsg property of the container, explaining why the validation failed.
When you want to enforce business rules before a record is inserted into or deleted from a record source, you use a different set of methods from the Validate() and ValidateRow() methods. When controlling the insertion of new records, you use the
PreInsertCheck(), PreInsert(), and PostInsert() methods. You must add the method code controlling whether the insertion should proceed to PreInsertCheck(), which is triggered before the application sends the instruction to insert the new record. If you
want to allow the insertion, enter the statement PreInsertCheck = Inherited.PreInsertCheck() (instructing the method to return TRUE) into the method code added to PreInsertCheck(). PreInsert(), on the other hand, is called immediately before the insertion
but after the decision to insert the record has been made. Finally, PostInsert() is triggered after the record has been inserted.
When you're working with master and detail records, it is often important to capture the insertion of detail records as well as master records. If you want to control the insertion of detail records, use the LinkPreInsertCheck(), LinkPreInsert(), and
LinkPostInsert() methods, which are triggered on the container displaying master records.
When controlling the deletion of records, you use a similar set of methods. PreDeleteCheck(), PreDelete(), and PostDelete() control the insertion of master records or records with no associated detail records. LinkPreDeleteCheck(), LinkPreDelete(), and
LinkPostDelete() control the deletion of detail records. Figure 41.9 illustrates a PreDeleteCheck() method, which enforces that the user must okay the delete operation.
Figure 41.9. Enforcing a deletion business rule.
Oracle Power Objects was designed to provide significant database integrity with respect to transaction-processing logic without requiring the developer to do any coding. Whenever you have a bound container loaded into memory, the application keeps
track of any inserted, deleted, or modified records through the Record Manager object. The Record Manager holds the record set queried for the container, including a record of all pending transactions to be performed on the record set. Each bound container
either has its own associated record set object or shares it with another bound container. Figure 41.10 illustrates what happens when a record is updated and the user attempts to close the window without actively committing or rolling back his changes to
Figure 41.10. Transaction-processing logic.
Each Record Manager object gains access to corresponding database objects through a session object. As is the case with other application objects, the session object has properties and methods associated with it, including the following transaction
Indicates whether there are any transactions pending for the session.
Commits transactions pending for the session.
Rolls back the last transaction set committed for the session.
Figure 41.11 illustrates the relationship between form objects, record managers, session objects, and database servers.
Figure 41.11. Relationship between forms, record managers, session objects, and database servers.
The application commits any transactions whenever the following occurs:
- The user presses the Commit button on the Runtime toolbar. The application then commits all work pending on the active form, including insertions, deletions, and updates, by calling the CommitForm() method.
- The application calls the CommitWork() or CommitForm() method. CommitWork() acts on the session, committing all pending work for a session, and CommitForm() commits the pending transactions for all sessions represented on an individual form.
The application rolls back transactions whenever the following occurs:
- The user presses the Rollback button on the Runtime toolbar. The application then rolls back the last transaction committed on the active form.
- The application calls the RollbackWork() or RollbackForm() method. RollbackWork() rolls back the entire transaction set last committed for a single session, and RollbackForm() rolls back the work in all sessions represented on a form.
Oracle Power Objects goes far beyond the non-data-centric capabilities of other products such as Microsoft Visual Basic, Microsoft Access, and PowerSoft PowerBuilder in enforcing multiple levels of application-based referential integrity. In Power
Objects, there is no programming required to enforce application-based referential integrity; all you need to do is simply select among the various levels from a pull-down list. By default, Power Objects enforces the highest level of referential integrity
by not permitting the deletion or update of a master (primary key) record if any detail (foreign key) records exist. Table 41.1 lists the levels of referential integrity enforcement.
Table 41.1. Client/server tools positioning.
Refuse if Children Present
You cannot delete or update a master record while there are detail records linked to it.
Delete Cascade or Update Cascade
The application automatically deletes or updates all detail records associated with the changed master record.
The application deletes or updates the master record but leaves all associated detail records untouched. The detail records are now "orphaned" because they do not correspond to any master record.
Figure 41.12 illustrates the actions that Power Objects takes when a user attempts to update or delete a master record when referential integrity is set to the highest level of Refuse if Children Present.
Figure 41.12. Highest level of referential integrity.
Assume that the referential integrity is set to Update Cascade and Delete Cascade, and the original DEPTNO is 10, but the user changes it to 11. The detail records acquire row-level locks and update as reflected in Figure 41.13.
Figure 41.13. Cascading referential integrity.
Assume that the referential integrity is set to Orphan Details, and the original DEPTNO is 10, but the user changes it to 11. The detail records are "orphaned" as reflected in Figure 41.14.
Figure 41.14. Orphan details referential integrity.
The Oracle Power Objects Form Designer coupled with the built-in transaction processing, application-enforced referential integrity support, and the overall data-centric orientation of the object model is a very capable design environment. Developers
can quickly prototype their applications, knowing that the default Power Objects application environment handles scrolling data, maintaining synchronization between views of the same data, protecting against the user making changes and accidentally
forgetting to save changes, and providing referential integrity. Power Objects applications have excellent data integrity and sufficient methods available so that developers can embed custom business rules.