This section contains the contents of the Overview chapter for the OO to RDBMS mapping framework from the ODBTalk 2.0 documentation. For enhancements implemented in the recent ODBTalk version 3 release, view the ODBTalk version 3 announcement.
ODBTalk 2.0 includes a framework or facility to handle the mapping of Smalltalk object oriented applications to relational databases.
Since most of the corporate data reside in relational databases, the issue of mapping an object oriented application or model to a relational database is frequently encountered by Smalltalk developers.
The ODBTalk 2.0 mapping facility consists of the following components or subsystems:
We describe them in this chapter. These subsystems collaborate with each other and together they form the OO->RDBMS mapping facility.
The ODBTalk workbench now includes a facility to define the mappings, and in the PARTS Workbench you can automatically generate forms based on the types which are defined in your image.
The type subsystem consists of the following classes:
A model is a collection of types. It is somewhat equivalent to a database schema or a catalog in a relational database.
A model is usually associated with a default broker. This broker is then used to store and retrieve the instances of the types defined in the model from the database.
A type in ODBTalk 2.0 is roughly equivalent to a database table.
The specification of a type includes:
There will usually be a type defined for every database table or view, the application needs to access. A Type is not a Class. You can define classes (and automatically generate them) for the types defined in your model. Note however that this is not required.
A type does not have to include all the columns of a database table or view. You may choose a subset of columns which is appropriate for your application. As well a type can include attributes which are not mapped to a database column. Such an attribute may be used to perform a computation (e.g. weeklyPay: hoursWorked * hourlyWage).
The keys of a type is the collection of mapped attributes (or table columns) used to identify the instances of the type (or rows of the table). There is only one key defined for a type. The key is used for comparing types (instances of a type are equal is they have the same type and their keys are equal) ,inserting new instances in the database and retrieving instances by key.
A type has two types of attributes:
The key of a type corresponds to the primary key of a table. You do not have to choose the primary key of a table. You can choose any set of attributes that uniquely identifies instances of a type as the key. The brokers use keys to perform inserts and selects (using the key) in the database.
A mapped attribute is an attribute of a type which corresponds to a column of the database table (or view). A mapped attribute has information about the column name it is mapped to and the Smalltalk class which will be used to store the attribute values (e.g. String, Integer, ByteArray ...).
Since mapped attributes exists to store values from table columns, they cannot be used for any other purpose. This is why Types can (and usually do) also have non mapped attributes.
A non mapped attribute of a type is an attribute which is not mapped to a database column. Non mapped attributes must be used for mapping relationships, and can be used to compute derived attributes or store any other characteristic of a type which is not stored in a database.
An non mapped attribute is used to define a relationship. The relationship can be of the following types:
Now a type is just a specification for its instances. When a relationship attribute (i.e. which is used to define a relationship) is accessed in an instance of the type, it will return either an LPCObject or an OrderedCollection of LPCObjects.
This explains why you need separate attributes for relationships. They are used to store the related objects.
Non mapped attributes can also be used for other things besides implementing relationships. If you use generated classes you may add directly instance variables and methods to your generated classes. When you do not generate classes, you can assign Smalltalk blocks to the non mapped attributes. They can therefore be used to perform computations, and provide extensions to types without having to define a class.
Relationship specifications are defined as instances of LPCObjectTypeRelationship. The relationship specification includes:
LPCObjectType can maintain a library of SQL statements. You can think of it as facility to store named queries. This is useful if for example you always use some queries to retrieve a collection of types (e.g. outstanding purchase orders, overdue accounts ...).
You can then execute these stored queries (Loading SQLs) by asking the broker to execute the named query. It will be retrieved from the Object TypeObject library (implemented by a Dictionary) and executed by the broker.
The workbench includes a facility to create and maintain Loading SQLs for your Object Types.
The LPCObject subsystem consists of two classes: LPCObject and LPCGeneratedClass. Instances of LPCObject contain instances of your Object Types.
An LPCObject is an instance of an Object Type. It is the mapped attributes of the instances of LPCObject that are eventually stored in the database. Rows retrieved from your database tables become instances of LPCObject.
LPCObject is a mechanism to manage instances of different object types with their own attributes, accessors and setters without having to create a Class for each object type.
All LPCObjects understand the following messages:
Of course LPCObjects also have a protocol to store/update and delete themselves in the database.
LPCGeneratedClass is an abstract class whose subclasses are the classes generated by the class generator. It is a subclass of LPCObject.
Instances of the subclasses of LPCObject are instances of Object Types. The main difference between them and instances of LPCObject is that the accessors and setters for the attributes are part of the generated class protocol. As well you can add your own method to the Generated Class.
Using subclasses of LPCGeneratedClass (produced by the class generator) may offer better performance than using LPCObjects. The trade-off is now your image may be bigger since it will contain more classes.
The broker subsystem is the interface between the Object Type subsystem and the ODBTalk base classes. It is responsible for retrieving and storing Object Type instances in the relational tables and mapping the two worlds.
It consist of two classes:
This class implements the interface between the Smalltalk world (through the Object Types) and the database world. It knows how to store, retrieve and delete Object Types from the database.
This is a private class which is used to transform query results into Object Type instances.
This subsystem has one class: LPCClassGenerator. It is used to generate Smalltalk classes from LPCObjectTypes.
The generated classes can have instance variables and accessors for their attributes (mapped and no mapped) generated automatically.
The generated class are subclasses of LPCGeneratedClass and inherit all the capabilities of LPCObjects.
The OO->RDBMS facility includes a subsystem integrated with the PARTS workbench.
The LPC PARTS catalog includes the following parts:
The PARTSLPCObjectType can generate TablePane layouts and the LPCPARTSLPCObject can generate forms with EntryFields for the attributes of Objects and Buttons for the relationships.
This facility enables you to visually generate applications based on the OO->RDBMS mapping facility.
The steps to create a model are as follows:
Copyright © 1996 LPC Consulting Services Inc.
Author: Ken Findlay kfindlay@ican.ca - last edited June 15th, 1996