Author

This document was written by Dave Rolsky with help from the POOP group list (poop-group (at) lists.sourceforge.net). In addition, some of the module authors, notably Chris Winters (SPOPS) and Matthew Simon Cavalleto (DBIx::DBO2) have contributed to the portions of this document covering their modules.

What is POOP?

POOP stands for Perl Object-Oriented Persistence. That sounds awful fancy but really it's really a simple concept.

Objects are cool. Objects are your friends. But objects can be bulky. Often, we don't want to go through the same work of creating objects from scratch every time a program is run. It would be nice if we could save them and avoid at least some of the work involved in their creation.

In addition, sometimes we simply want to save the state of an object from one invocation of a program to the next.

Often, this saving consists of mapping them onto a relational database. Relational databases offer a lot of power but they don't always translate to objects that well. In addition, we may have existing data in a database that we'd like to deal with as objects.

Other times it is preferable to save objects to a plain file, or a DBM file, or to a wax cylinder. All of these things come under the heading of object-oriented persistence.

Unsurprisingly, there is more than one way to do this. It wouldn't be Perl if CPAN didn't have at least 37 modules covering every possible variation on the topic! Ok, its really not that crowded, and the variety of modules in this case is mostly justified. This is a complex, multi-faceted problem, and so it is unsurprising that different people have taken different approaches to the topic.

There are several fairly distinct categories into which various projects can be placed:

For all of the tools which are examined, we will list:

RDBMS-OO Mappers

These modules all aim to make it possible to use objects to access data stored in an RDBMS. They vary in many respects in terms of their complexity and feature set.

The following features are addressed:

Tools:

Class::DBI

 Author Emeritus:   Michael Schwern <schwern (at) pobox.com>
 Current Developer: Tony Bowden <kasei (at) tmtm.com>
 Homepage:          http://www.class-dbi.com/
 Latest Version:    0.94 - August 31, 2003
 First Release:     December, 1999

Supported databases

Any database for which there is a DBD module.

SQL Abstraction

It abstract simple SQL selects, inserts, updates, and deletes. Selects can be done via a table's primary key or by using an equality or 'LIKE' comparison on a single column. It is not possible to select based on other SQL operators or against multiple columns at once.

It is possible to associate arbitrary SQL statements with a class that may be as complex as needed, but these are specified in the form of raw SQL.

It does not support joins directly but see the Table Relationships section below.

Invalid SQL

This is not possible with any of the Class::DBI built-ins, but it does allow you add your own queries in raw SQL via Ima::DBI, from which Class::DBI inherits, and these may of course be invalid

Deferred/Preloaded data retrieval

It is possible to instruct Class::DBI to defer column loading by defining usage patterns (groups of related columns) as well as telling it to always load only certain columns when an object is created.

Table Relationships

Class::DBI supports arbitrary 'has-a' and ' 'has-many' relationships between classes, representing 'many-to-one' and 'one-to-many' associations. These can be combined (although not automatically) to represent many-to-many relationships.

It assumes that relationships are dependent and does a cascading delete by default.

One notable feature of its relationship support is that related classes need not be using the same database for the relationship to be handled properly.

Multiple rows and cursors

Multiple rows can be retrieved either all at once or via an iterator object.

Caching

There is no built in caching support for the objects themselves. The data itself can be cached as mentioned in the Deferred/Preloaded data retrieval section above.

Auto-generated methods

Class::DBI auto-generates methods for fetching columns and for fetching related objects.

Triggers/Hooks

You can setup post-select triggers, as well as pre- or post- triggers for inserts, updates, or deletes. All triggers are defined per-class, and a class may have multiple triggers for a given point.

In addition, you can define constraints, which are callbacks that validate the value of a given column for a class. These callbacks are called whenever an attempt is made to create or update an object.

Documentation

Class::DBI is very well documented and fairly easy to use and understand. The documentation contains enough examples to help you understand how to use the module.

License

GPL/Artistic disjunction. The same as Perl itself.

Support

Support for this module is available on the POOP group list (poop-group (at) lists.sourceforge.net).

Status

Actively developed and supported by the current developer. In addition, there are a number of other modules in the Class::DBI namespace developed by others which enhance the basic Class::DBI features.

Alzabo

 Author:         Dave Rolsky <autarch (at) urth.org>
 Homepage:       http://www.alzabo.org/
 Latest Version: 0.72 - April 12, 2003
 First Release:  July 4, 2000

NOTE: I am the author of Alzabo, and biased. So there.

Supported Databases

MySQL and PostgreSQL. Future versions will support other databases but doing so is non-trivial.

SQL Abstraction

Alzabo abstracts almost all possible SQL operations, including simple selects, deletes, inserts, updates, as well as multi-table joins (including right and left outer joins), aggregate functions, complicated where clauses, group by and order by, and limits with offsets.

It does not yet support unions.

Invalid SQL

This is almost impossible with Alzabo. The only way to do this would be through the use (abuse) of a RDBMS's native functions (such as COUNT or MAX).

Deferred/Preloaded data retrieval

Alzabo supports this in exactly the same way as Class::DBI (I stole it from Schwern). It is possible to instruct Alzabo to retrieve multiple columns at once, defining usage patterns (groups of related columns), as well as telling it to always load certain columns when an object is created.

Table Relationships

Alzabo supports any type of relationship relationship, allowing you to specify cardinality and dependency information.

Once Alzabo has this information it is capable of automatically following these relationships.

In addition, it is capable of maintaining referential integrity based on this information.

Multiple rows and cursors

Alzabo always uses cursors when a query might return multiple rows. When a query must return only a single row, cursors are not used.

Caching

Alzabo is capable of caching column data inside row objects. In addition, row objects themselves are cached so that they are re-used as much as possible.

Alzabo's caching will be greatly simplified in next release (0.80).

Auto-generated methods

Alzabo can auto-generate a very large number of methods, including methods for fetching column data, methods for retrieving rows in other tables based on any type of relationship, and more.

Triggers/Hooks

Hooks are integrated with the method auto-generation mechanism, allowing you to have certain methods called before and/or after insert, update, delete, and select operations. Hooks are defined on a per-table (class) basis.

Documentation

Alzabo has very extensive documentation of its features. However, one very valid complaint I have heard is that this extensiveness is a bit overwhelming. This makes it difficult for people to know where to go after reading the introductory material. In the future I aim to expand the introductory material included with Alzabo in order to help obviate this problem.

License

GPL/Artistic disjunction. The same as Perl itself.

Status

Actively developed and supported by the author.

Support

Support for this module is available on the alzabo users list (alzabo-general (at) lists.sourceforge.net).

Other

In addition to being an RDBMS-OO mapper, Alzabo is a full fledged data modelling tool. It has a web based interface which allows you to create a schema consisting of tables which contain columns, indexes, and foreign keys. It is possible to create a schema from scratch or to reverse engineer an existing schema, though currently this reverse engineering does not understand foreign keys.

Each schema keeps track of when it was last instantiated in an RDBMS backend and Alzabo is capable of generating the SQL necessary to turn the RDBMS schema into something matching the state of the schema object (an SQL 'diff').

Creating a data model is how Alzabo obtains the information it needs to act as an RDBMS-OO mapper.

A Mason-based web interface for Alzabo's data modelling functions is now distributed separately in the AlzaboGUI::Mason package.

DBIx::RecordSet

 Author:         Gerald Richter <richter (at) dev.ecos.de>
 Homepage:       http://perl.apache.org/embperl/
 Latest Version: 0.24 - July 10, 2001
 First Release:  May 1, 1998

Supported databases

Any database supported by one of the following: DBD::CSV, DBD::Informix, DBD::Interbase, DBD::mSQL, DBD::mysql, DBD::ODBC, DBD::Oracle, DBD::Pg, DBD::Solid, DBD::Sybase.

Extending this module to support other drivers would require only a small amount of coding.

SQL Abstraction

This module supports arbitrarily complex conditional select, updates, and deletes.

It is possible to apply order by and group by clauses to operations, as well as limits.

DBIx::RecordSet support all types of joins. Its query syntax is very flexible, and as a last resort it is possible to pass in snippets of SQL.

Invalid SQL

Most of the time, this will not be possible. If, however, you pass in a SQL snippet as part of a query, there is no way to validate this.

Deferred/Preloaded data retrieval

There is no way to defer the loading of given columns for a select. However, it always possible to easily specify only those columns which are needed at a given point in your code.

It is possible to specify a set of rows to be prefetched when tying a hash to set of rows.

Table Relationships

DBIx::RecordSet supports arbitrarily complex joins, including outer joins and unions.

Multiple rows and cursors

DBIx::RecordSet always returns cursors.

Caching

There is no built in caching support.

Auto-generated methods

DBIx::RecordSet does not auto-generate any methods.

Triggers/Hooks

DBIx::RecordSet does not support any triggers/hooks.

Documentation

This module has extremely thorough documentation. It is chock full of helpful examples for all of its features.

License

GPL/Artistic disjunction. The same as Perl itself.

Support

Support for this module is available on the dbi users list (dbi-users (at) perl.org).

Status

The author hasn't released a new version in quite some time, though he is still active in the Perl community. This module still has active users. The author will accept patches from others, though he has not had time to actively develop the module recently.

Other

DBIx::RecordSet offers both OO and tied-hash access to data. The tied hash implementation can be used both for retrieving and updating data in the database.

It also has the capability to set up filters to pre- or post-process data going into/coming from the database.

DBIx::DBO2

  Author:         M. Simon Cavalletto <simonm (at) cavalletto.org>
  Homepage:       http://www.evoscript.org/DBIx-DBO2/
  Latest Version: 0.006 - April 30, 2002
  First Release:  July 10, 2001

Supported databases

Any database supported by one of the following: DBD::AnyData, DBD::CSV, DBD::MySQL, and DBD::Pg.

Providing support for other drivers involves creating a DBD-specific subclass of DBIx::SQLEngine (which will be loaded via DBIx::AnyDBD when appropriate), and should require a relatively small amount of coding for most DBD modules.

SQL Abstraction

This module supports moderately complex selects, inserts, updates, and deletes, based on the DBIx::SQLEngine abstraction layer. It is possible to apply order by and group by clauses to operations, as well as limits.

Inserts with sequences are supported, even for DBDs which don't have native sequence/auto_increment equivalents. The base Record class does not support joins, although the underlying DBIx::SQLEngine classes do, and it is possible to provide your own query logic in a subclass.

Invalid SQL

The automated SQL generation should produce valid SQL but any sort of query which requires you to use the underlying DBIx::SQLEngine interface will require you to pass in snippets of SQL that may be incorrect.

Deferred/Preloaded data retrieval

There is not yet any way to defer the loading of given columns for a select. However, it always possible to specify only those columns which are needed at a given point in your code.

Deferred loading of additional columns is expected in an upcoming release.

Table Relationships

DBIx::DBO2 supports both many-to-one relationships. The user can choose how to implement referential integrity, either using cascading delete, nullify after delete, or restrict delete rules. You can establish relationships between classes regardless of whether their data is actually stored in the same underlying SQL database.

Multiple rows and cursors

DBIx::DBO2 currently returns multiple rows all at once. A RecordSet object similar to a cursor is used by it does not yet handle incremental retrieval.

Support for cursors and automatic iteration with closures is expected in an upcoming release.

Caching

There is no built in caching support.

Support for LRU caching and ensuring that there is only a single instance of a given object in memory at any time are both expected in an upcoming release.

Transactions

DBIx::DBO2 does not support transactions.

Basic transactions for drivers that support them are expected in an upcoming release.

Auto-generated methods

The included DBIx::DBO2::Fields package can generate a wide variety of methods, including customized accessors for each type of field or relationship. These currently require explicit declarations.

Support for automatic detection of database columns and subsequent method generation is expected in an upcoming release.

Triggers/Hooks

A callback mechanism allows you to specify method names or arbitrary subroutines to be called as pre- or post- insert, update, delete, or select hooks. You can define these hooks globally for all record classes, for a particular class, or even for a particular object instance.

Documentation

The documentation for this module is still fairly rough. In particular, it lacks non-reference material to introduce the its idioms.

License

GPL/Artistic disjunction. The same as Perl itself.

Support

Support for this module is available from the author. The author is also available for support contracts or consulting engagements.

Status

DBIx::DBO2 was recently released to CPAN after several years of in-house use, and is currently in use on several e-commerce sites. The author is still actively using and supporting this distribution.

OO Persistence Tools

Unlike the previously discussed tools, an OO persistence tool is designed to allow you to add persistence features to your objects. Object persistence involves the serialization of objects to some storage format and then reconstistuting them back into memory, while retaining all of their essential properties such as their data and their relationships to other objects.

The following features are addressed:

Tools:

Tangram

 Author Emeritus:    Jean-Louis Leroy (Sound Object Logic) <info (at) soundobjectlogic.com>,
 Current Developers: Sam Vilain (sam (at) vilain.net) and others
 Homepage:           http://www.tangram-persistence.org/
 Latest Version:     2.06 - July 16, 2003
 First Release:      mid-1999 (?)

Supported Storage Formats

Tangram currently only supports storage in an RDBMS. Tangram comes with a 'vanilla' backend module designed to support any RDBMS that understands standard SQL and for which there is a working DBI driver. In addition, it has custom backends for MySQL and Sybase.

Future versions of Tangram will support the storage of objects using XML files.

Queries and Cursors

Tangram supports arbitrary queries based on an object's properties ("Find me all people with the first name of 'Bill'"). Tangram can return query results either as an array of objects or via a cursor.

Polymorphic Retrieval

Tangram support polymorphic retrieval of objects.

Object Relationships

Tangram saves an object's relationships to other objects.

Caching/Optimizations

Tangram makes sure that there is only a single instance of a given object in memory at any time. While this is done for data integrity purposes, not caching, it does have the effect of caching object retrieval.

Transactions

Tangram supports transactions if the backend storage format it is using supports them. In addition, it supports nested transactions.

Documentation

Tangram has fairly thorough documentation, including a nice "Guided Tour" which walks the reader through most of the major features of Tangram.

My one complaint about the documentation is that after reading the "Guided Tour" it is not clear what to read next. I suspect that it is in fact probably not necessary to read the documentation for many of the modules, which seem to be for Tangram's internal use only.

An indication of where to go after the guided tour would be helpful.

License

Tangram is licensed under the GPL.

Support

Support for Tangram is available via the tangram-users mailing list (tangram-users (at) lists.sourceforge.net).

Status

Tangram is actively developed and supported by Sam Vilain and a group of other developers. Development discussion occurs tangram-t2-maintainers. See http://www.perlfect.com/mailman/listinfo/tangram-t2-maintainers for more details.

Other

Jean-Louis Leroy and Sound Object Logic are no longer using or maintaining the current version of Tangram (version 2). They are using, and planning to release, a new version called T3, which will support multiple languages with multiple storage backends.

I saw Jean-Louis dance at TPC 5.

SPOPS

 Author:         Chris Winters <cwinters (at) intes.net>
 Homepage:       http://www.openinteract.org/SPOPS/
 Latest Version: 0.79 - Jun 10, 2003
 First Release:  0.32 - October, 2000

SPOPS stands for Simple Perl Object Persistence with Security.

Supported Storage Formats

SPOPS supports storage in Oracle, PostgreSQL, MySQL, Sybase, Interbase, SQLite, LDAP, GDBM files, and flat files. Certain features are only available with certain backends. Additionally, most DBI-accessible databases, including those accessed through ODBC, can be used as read-only datasources if an SPOPS-specific driver is not available.

Queries and Cursors

The types of queries allowed vary based on the storage format. When storing data in an RDBMS, SPOPS allows the user to pass in SQL snippets to retrieve a set of objects. Similarly, LDAP queries can pass query filters to the driver. Otherwise, you are limited to retrieving objects by their id with flat files or GDBM files. GDBM file storage also supports retrieving all objects of a specific class, but this retrieval is not polymorphic.

SPOPS can return the results as a cursor (referred to as iterators in the SPOPS documentation) or as an array.

Polymorphic Retrieval

SPOPS does not support polymorphic retrieval, although there is an extension called ESPOPS (Enhanced SPOPS) available at http://www.pserc.cornell.edu/ESPOPS/ which implements polymorphic retrieval for MySQL datasources.

Object Relationships

Recent releases of SPOPS now include the ability to declaratively specify relationships between classes as "has-a" and "links-to" relationships. An class that "has" another class contains that class in a one-to-one or many-to-one relationship. A class that links to another class has a one-to-many or many-to-many relationship with that class.

Caching/Optimizations

SPOPS supports a column grouping feature similar to that in Class::DBI and Alzabo. In effect, this allows you to only load certain properties on an object into memory, without loading the whole thing all at once.

In addition, it has hooks for caching, though it does not implement any caching itself. The end programmer must provide a class to handle the object caching.

Transactions

SPOPS does not support transactions. Since the DBI handle is available through the object, this can be implemented on an as-needed basis or through a wrapper class. See note on code generation below for more details.

Other

SPOPS has a number of unique features. First of all, it has a feature called "rulesets" which allow you to define callbacks for various stages of handling an objects, such as before and after removing an object from the storage mechanism.

Additionally, you can define custom behaviors that are generated along with a class at startup. For instance, you could create a class to use transactions and define the serialization methods to rollback on failure.

It also supports a per-object security model which allows you to define Unix-like read/write permissions for specific users and groups of users. Users and groups are objects provided by the end programmer which must implement an interface specified by SPOPS.

Multiple-field primary keys are supported for DBI datasources.

You can specify a field mapping to refer to an object's properties by one or more names.

The distribution includes tools for exporting data to a Perl data structure, XML, and SQL statements, among others. You can also import from different types of Perl data structures.

Documentation

The documentation for SPOPS is quite extensive. As with any large system, wrapping your brain around what it can do is non-trivial. After reading the introductory documentation in the SPOPS module, it's not immediately clear where to go next. The SPOPS::Manual seems promising, but is not complete. However, the documentation has improved quite a bit since the last version I looked at (0.61).

License

GPL/Artistic disjunction. The same as Perl itself.

Support

Support for SPOPS is available via the OpenInteract-Help list (openinteract-help (at) sourceforge.net).

Status

Actively developed and supported by the author.

More Info / Discussion

See the POOP-group mailing list at http://lists.sourceforge.net/lists/listinfo/poop-group for discussion of general POOP matters. There is also an announcement-only list, POOP-scoop, at http://lists.sourceforge.net/lists/listinfo/poop-scoop.

Generated from Id: poop-comparison.pod,v 1.35 2003/09/30 15:47:47 autarch Exp.