While working on the new Cincom® ObjectStudio® mapping tool that generates code for the object-relational mapping framework GLORP, we built some GUI for handling database converters.

While working on the new Cincom® ObjectStudio® mapping tool that generates code for the object-relational mapping framework GLORP, we built some GUI for handling database converters.

GLORP Database Converter

Let’s take a quick look at today’s GLORP database converters. Database converters are used for converting back and forth between database and object representations. They are used by Direct Mappings where one column of a table is mapped with one instance variable of a class. A Direct Mapping in GLORP is normally coded like this:

(aDescriptor newMapping: DirectMapping)

from: #catalogID

to: (table fieldNamed: ‘CATALOG_ID’).

Depending on the information in the table and class model descriptor, GLORP automatically assigns a database converter to the mapping. In this particular case, since catalogID is a string and the field CATALOG_ID is defined as a varchar:, 255 GLORP will assign it the DelegatingDatabaseConverter named stringToString. So if you want different behavior, you can write your own converter and assign it to the Direct Mapping with the converter: setting method.

Types of Converters

In GLORP, there are three kinds of database converters:

Null converter

Delegating Database converter

Pluggable Database converter

Null Converter

This is a no-op converter. It simply returns the value that it receives from Smalltalk or the database.

Delegating Database Converter

Here we delegate the conversion to another object; typically this will be the database platform. The creation of the converter is also done on the instance side of the DatabasePlatform. Let’s take a look at the dateConverter. On DatabasePlatform, it’s defined as:

^DelegatingDatabaseConverter

named: #date

hostedBy: self

fromStToDb: #toDate:for:

fromDbToSt: #readDate:for:

Each database platform can have its own implementation of the fromStToDb- and fromDbToSt-defined methods, but a platform can also override the entire delegating database converter by its own definition.

The methods defined in the fromStToDb and fromDbToSt have two arguments. The first one is the object that needs to be converted, and the second one is the database field type definition.

If we look at the implementers of toDate:for:, we see that two classes have this method implemented.

DatabasePlatform>>toDate:for:

toDate: anObject for: aType

anObject isNil ifTrue: [^nil].

anObject class = Date ifTrue: [^anObject].

^anObject asDate.

and

SQLite3Platform>>toDate:for:

toDate: anObject for: aType

| stream |

anObject isNil ifTrue: [^nil].

stream := String new writeStream.

self

printDate: (super toDate: anObject for: aType)

isoFormatOn: stream.

^stream contents

SQLite doesn’t support timestamps, and all Smalltalk objects must be converted to strings before they can be handed to the database.

On the other hand, readDate:for: only has one implementer since all data from the database is normally received as a String, and the same conversion has to be done to convert to a Smalltalk date object.

You can also override the entire converter in a database platform. For the dateConverter, this is done in the SQLServerPlatform.

^DelegatingDatabaseConverter

named: #date

hostedBy: self

fromStToDb: #dateToTimestampConversion:for:

fromDbToSt: #readDate:for:.

Since SQLServer doesn’t have date types, the date must be converted to a timestamp.

Pluggable Database Converter

The Pluggable Database Converter is a custom-defined conversion specified by two blocks. There’s a dbToSt and a stToDb block. Both blocks take one argument, which is the value that needs to be converted. We’ll illustrate this with a very simple example. Let’s assume we need to store a value in the db, and for some odd compatibility reason, we need this to be shown in uppercase since some stored procedures were made to process these as uppercase values. In Smalltalk, we prefer to have the value in lowercase since our users find it better to have it on the GUI in lowercase. You would define a converter like this:

| obj |

obj := Glorp.PluggableDatabaseConverter new.

obj

name: 'Lowercase';

dbToStConverter: [ :aValue | aValue asUppercase];

stToDbConverter: [ :aValue | aValue asLowerCase].

^obj.

These converters can be defined in your own classes and accessed there by the descriptor system, or you can define the converters directly in your descriptor system.

Using Converters

You notice that converters have names. These are just for information; they’re not used as a key in some global dictionary. If you want to use a specific converter for your mapping, define it as follows:

(aDescriptor newMapping: DirectMapping)

from: #isCorrect to: (table fieldNamed: 'IS_CORRECT');

converter: (self platform converterNamed: #booleanToStringYesNo)

or

(aDescriptor newMapping: DirectMapping)

from: #description to: (table fieldNamed: ‘ART_DESCRIPTION);

converter: (PluggableDatabaseConverter new

name: ‘Lowercase’;

dbToStConverter: [:aValue |aValue asUppercase];

stToDbConverter: [:aValue |aValue asLowercase];

yourself).

Next to the converters we also have a mapping that can do its own specific conversions―AdHocMapping … but that’s for a future article.

Leave a Reply

Search Our Site

Search for:

Promotions

Customer Quotes

“Compared with using COBOL and CICS, maintaining object-oriented applications is much easier. With ObjectStudio, the benefits and the ease of use are really there." - Larry Lowden, Application Development Manager at the Wisconsin Department of Revenue