Data Modeling with Alzabo

Reuven takes a detour this month and shows you how to bridge the object-relational gap.
Caches and Exceptions

If Alzabo simply provided a set of methods that create SQL, it wouldn't be a very powerful tool. However, Alzabo provides caching and exception-handling as part of its suite of tools, making it easier in some ways to work with databases.

Alzabo's caching functionality keeps a table in memory rather than returning to the database server each time we request a value from it. Obviously, caching isn't appropriate for tables that change on a regular basis, but for tables that rarely change, you can activate the cache and enjoy a nice boost in speed.

You can activate caching by loading the Alzabo::ObjectCache module in your program. The RowCursor object, which we used to retrieve rows in Listing 2, returns Row objects with each iteration of the next_row method. See the documentation for Alzabo::Runtime::Row and Alzabo::ObjectCache for information about the different kinds of caches available to you, as well as the issues associated with them.

Alzabo also uses Perl's built-in exception-handling system, meaning that it invokes “die” if something goes wrong. Therefore, you should wrap your Alzabo-using programs (or individual calls within them) in “eval” blocks:

# Try to run this code
eval {
    my $row_cursor =
            where => [[$people->column('first_name'),
                       'LIKE', $look_for_name],

You can find out if something went wrong by checking the special Perl variable $@, which is set if an error occurs within the previous eval. But Alzabo uses the Exception::Class object (available from CPAN) for more sophisticated exception-handling in Perl. The $@ variable isn't set to a text string describing the error, rather it is set to an instance of the appropriate exception class. You can thus test $@ with UNIVERSAL::isa to determine just what kind of object it is and what kind of problem occurred within your code. The Mason component common/exception, installed under the alzabo directory in your Mason-controlled Apache content directory, demonstrates how to do this in detail.


There are obviously costs associated with Alzabo, as with any tool that tries to bridge the object-relational gap. For starters, SQL is a fairly standard means for working with relational databases. Using Alzabo means you will be moving away from that standard and toward a different solution that is incompatible with anything else. I'm not opposed to new ways of doing things, and there are a number of significant advantages to using Alzabo. That said, I'm always cautious about doing old, standard things in new, nonstandard ways.

While I normally prefer to create my tables using handcrafted SQL, that technique doesn't scale above 10 or 20 tables without forcing me to scroll wildly within my Emacs buffer. Alzabo's web-based schema design tool does make it easier to keep track of a large number of tables to create relations between them and modify them. I recently spent half an hour trying to remember how Oracle's syntax was different from that of PostgreSQL and would have greatly benefitted from a tool like Alzabo.

As we saw earlier, creating complex queries based on equality isn't difficult within Alzabo, even when those queries include OR and AND operators. The Alzabo::Runtime::Table object includes a function method, which is meant for executing arbitrary SQL functions. However, I found it difficult, and in some cases impossible, to create Alzabo WHERE clauses that would let me create an SQL query based on multiple function calls. I admit that I'm relatively new to Alzabo and only tried it for an hour or two, but a query that took me 20 seconds to write in SQL shouldn't take much longer than that in Alzabo.

One of the more difficult issues when mapping objects to relational databases has to do with joins. Joins make a lot of sense when working with tables, but the meaning is less obvious when working with objects. Alzabo does have some built-in support for joins, but it is marked as being largely new and experimental.

Finally, there is also a speed trade-off associated with any middleware layer. The speed differences between Listings 1 and 2 were quite noticeable when I executed them from the command line, owing in no small part to the fact that using Alzabo imports a large number of Perl classes. In a mod_perl environment (where Alzabo is designed to shine), the speed differences will be much smaller, since much of the time is spent loading different modules from disk. Because mod_perl compiles programs only once before executing them, the speed difference between Alzabo and raw DBI calls is probably not that great.