| Module Info
| Add a review of Class-DBI
When I was first introduced to Class::DBI in 2004 it was a breath of fresh air. Suddenly all the boring SQL didn't have to be there and I could focus on the task at hand. Sure, it had some warts but those could be worked around.
After using Class::DBI on some large-ish projects with a mod_perl-based web interface it became clear that those warts were viewed as "features" and were simply not going to be fixed. The rest of the Camel herd ran off to DBIx::Class (and far, far, far away from "icky" SQL).
If you like the Class::DBI interface but want better performance, clean transactions and something that's not abandoned - check out Class::DBI::Lite. For most projects it's a drop-in replacement and for the rest the changes are minimal.
Class::DBI is a very useful database abstraction.
I'd previously called Class::DBI abandonware, due to an 18 month drought of releases and the seemingly bizare refusal of the author to integrate and release bugfixes the user community were sending in.
It also does some tasks quite a weird way, in particular the LiveObjects system can lead to some fairly ugly situations/bugs, and it isn't possible to create a new object and pass it around to be worked on _before_ the first commit to the database.
(Most other systems I've seen have some sort of ->store method which does either ->insert or ->update depending on whether the object is new or not).
HOWEVER, now that the release drought is over (and how!), and the author has become much more response (if only to rt.cpan.org) I think most of these problems will gradually be fixed.
Class::DBI seems to be alive again, and so I'm happily rerating it. Bugs and nigglies aren't anywhere near so much of a problem when you know they are going to be fixed.
This is a great module to remove the tedium of embedding SQL all throughout your programs or otherwise having to deal with it. Class::DBI provides easy to use relations between tables, triggers and allows much SQL (particularly updating and deleting) to be abstracted away. The biggest problem I have had is that although there is a lot of documentation there are a lot of very simple questions that don't get answered.
I have been using Class::DBI for about a year, as I have needed more it has provided what I needed after reading through the documentation.
I have also built several subclasses that change the behaviour a great deal and have found that on the whole it works very well when subclassing although it would be nice if the SQL building was componentized a little more with less of a magical interface, this can be worked around trivially though using the methods provided or writing your own.
I really enjoy Class::DBI, it has made a couple projects relatively painless and fun. But this could be a much more powerul module if there was more powerful documentation. The current documentation forces you to experiment and divine things from Ima::DBI or surf wishfully for related modules on CPAN, but it actually is not that hard to make new queries for all of your classes at once, or to define new ones at runtime.
I have wondered if some speed problems I had were due to Class::DBI, reading the comments here it seems so, at least in part.
I have had trouble (undoubtedly my fault) with objects that forgot to load more than the Essential attributes when asked for them, so sometimes would force load of the entire object to solve that problem.
Some of the errors I have often had:
Can't locate object method "name" via package "WebApp::Company" and similar. In this case, I wanted to say $companyname = $user->person->company->name but Data::Dumper showed that $user->person->company returned an object blessed as WebApp::Company but it only included the Essential method "id". I had to re-retrieve the Company object.
Subroutine WebApp::Coach::sql_allids redefined at /usr/lib/perl5/site_perl/5.8.0/Ima/DBI.pm line 375.
search_allids() already exists at /var/www/lib/WebApp/Utils.pm line 1243.
prepare_cached(select now()) statement handle DBIx::ContextualFetch::st=HASH(0x901bf44) still active at /usr/lib/perl5/site_perl/5.8.0/Ima/DBI.pm line 391.
The above errors are undoubtedly my fault but the messages seem oblique and due to design issues which were not obvious on my first, second, and tenth readings of Class::DBI documentation. I am not worried about them now although possibly worried about potential memory leaks if I used it in mod_perl is this a reasonable worry?
A lot more information on optimization, and creation of preset queries that use both sql and perl logic would be nice. There was a hint in the has_many section about this, but as an example of what not to do. I think that in the real world you end up needing to do some things that are not covered by Class::DBI and these are potential targets for future development.
Also on use with CGI::Application and sessions (which I liked). I think I saved some time storing object in session table between pages.
I have to do some profiling to see how much time it is using but for a project where I was willing to trade execution time for speed in development, I was quite happy. Now I'd like to see some more documentation or more in the cookbook, I think this is the highest priority before other new methods.
Class::DBI is a work of beauty. It makes using databases really convenient and offers elegant ways of specifying data relationships.
The one big gripe I have about the module is the speed hit that comes with the elegant interface. The module takes forever to compile, but that's what we have mod_perl for.
I'll give an example: If you fetch more than a thousand or so records from a database and access their attributes, you'll end up calling numberOfRecords * numberOfAttributes accessor methods. On my humble server, that means waiting 10 seconds for the records to show up in my browser. 8 seconds of those are spent accessing two attributes of 1344 records. (Those 8 seconds are accounted for just by the method calls.)
I was unable to make the program run fast enough using Class::DBI. Thus, I switched to plain DBI and the request now takes significantly less that a tenth of a second to complete.
It took me a while before getting around to trying Class::DBI.
I really like it a lot more now, but it's not the easiest thing to use for a pre-existing database that may not have the best schema design in the world.
Sometimes simple database queries can be awkward, and it may take a while to debug the class design for joined tables.
It takes getting used to the iterator "pattern' of retriving database records. (I'm rather ambivalent about that style of programming.)
It's also awkward to specify dynamic connection parameters, but it can be done with some expiermentation. It's just not well documented.
Note: my review is for 0.95, because i cannot get 0.96 working on my platform. and the rating system will not let me specify an earlier version.
Database abstraction at an extremely productive level.
Lots of declarative logic and lots of under-the-cover smarts, hiding the boring and repetitive parts from you.
Some of the croak error messages could be a bit more helpful, and possibly not croak at the level _above_ where you are coding.
Class::DBI permits me to apply object-oriented techniques to my database, and to hide the complexities of SQL behind objects. I can finally centralize my application logic without having to resort to any oddities. Overall, I'd say this package is a must for anyone developing database-based applications.
Class::DBI makes database-intensive projects seem causal. It creates a neat wrapper around a database record, allowing you to maniplulate your database in an object-oriented way. Relationships between tables can be mapped in your objects, making it easy to get things done.
There are some limitations and a bit of awkwardness when doing complex sql. If your needs are fairly simple, and your complex joins are few, then this is worth checking out. It especially works well in a templated enviroment (like HTML::Mason) where you don't want to see SQL in Perl in HTML. Class::DBI helps make your code more readable.
Over the last couple of years, Class::DBI has continued to evolve into a mature set of tools. Be sure to check out triggers, inflate/deflate, and data validation.
Class::DBI is a great idea, and as I find my time to hack dwindling, I know that I need to invest the time to learn how to use it.
However it is not for the faint of heart, and given the current state of the documentation (which is exceptional, but still insufficient for this complex module), a subscription to cdbi-talk is something of a requirement.
Enough can not be said about how simple the debugging becomes when you use this module. I use this module to create almost all of my web-based DBI projects now. Thanks Tony!
Class::DBI is the first OR mapper in Perl which i've tried and actually continued to use. It's very perl like in that it makes easy things easy, and hard things possible by allowing you to drop back in to the normal DBI functions.
Converting a web app with 23,000 lines of code to using Class::DBI cut out 10,000 lines of code. I found that i was able to do the boring work of pulling data out of the database and constructing objects much faster with CDBI than what i had before which was just using DBI and Class::Accessor.
I see two major faults with CDBI. One is that it tends to hit the database a lot. It doesn't do joins, but rather separate selects. This means what was one select with a 7 way join has become 14 selects. Other times i've seen code which used to be one or two selects become dozens or hundreds. Acts which would make any DBA cringe. There has been some talk about improving the joining functionality within CDBI. Also there is some idea to add caching, which would significantly improve things.
CDBI has a good interface for overriding it's functions to improve functionality and provide customs cases. This is vital for anybody using CDBI for non-trivial projects.
The other issues is that despite the copious documentation there still isn't nearly enough. This is also something which i expect to improve with time. The gurus on the CDBI list have been very good about nicely responding to questions and reading the archives can make up for the 'missing manual'.
All in all, it's not a magic bullet. I have fears about it's scalability and performance on production applications but that's overweighed by the huge improvement in programmer efficiency.
I found this module because I wanted persistent objects that are stored in a database, but you can use it for far more than that.
If you happen to write similar code over and over again using the same database tables, take a look at this module: it will make your life so much easier!
And what I also find very useful is the simulation of foreign keys, even if the db-engine you're using doesn't support them. That makes writing either nested loops in your Perl code or writing complicated joins in SQL obsolete for selects. And it helps keeping referential integrity when making deletes.
The documentation is also very good: clear and concise.
Finally a simple and intuitive interface for databases. Thanks!
I was sceptical about this module for a long time, but once I started working with it I found it absolutely joyful; there are a huge bunch of SQL abstraction layers out there, but I think this is definitely the most Perlish and the easiest to use.