MyMonkName has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

So I just perused the documentation for Class::DBI ("a convenient abstraction layer to a database") and DBIx::Class ("allows abstract encapsulation of database operations") and I am struggling to see the point of using such a module.

I am not exactly a newbie with perl, although as somebody who learned it in the course of sys-admin/ops type work there was correspondingly less need for making everything into an object. That said, I understand perfectly well the reasoning behind OOP for software development, and a fortiori, modular code in general.

So I know there are dissenters from the OOP camp as a whole. That is not the hornets nest I want to kick at. I'm just wondering what benefit there is to replacing the conciseness of a SQL statement (which can be wrapped up into a method anyways, right?) with what looks like a mess of hashrefs that has to be over-ridden whenever there is something complicated to do anyways.

It seems this is touching on what Wikipedia calls the object-relational impedance mismatch but on my level of experience with these modules (which is admittedly nil) I'd hesitate to call it a "solution" as such. Am I not getting it? Anyone care to explain how this approach has made easy things easy and hard things possible, for them?

Thanks!

Replies are listed 'Best First'.
Re: Why use an OO -> SQL mapper module?
by BrowserUk (Patriarch) on Aug 11, 2011 at 17:49 UTC

    If your application is naturally OO, and is not self-contained, then you need to persist your objects between runs, then Object-relational mapping makes a lot of sense.

    If your application processes bulk data, manipulated en-mass using complex queries and joins, OO-relational mappings tend to get in the way more than help.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Why use an OO -> SQL mapper module?
by Your Mother (Archbishop) on Aug 11, 2011 at 17:59 UTC

    DBIx::Class (DBIC) is generally preferred [citation needed] over Class::DBI (CDBI) for the last few years; speed and flexibility the main reasons.

    You can search the monastery for quite a few nodes discussing these kits and several others worth considering; Perl ORM comparison (Class::DBI vs. DBIx::Class vs. Rose::DB::Object); google:site:perlmonks.org dbic cdbi.

    With DBIC there is not really an impedance mismatch because it has the meta-considerations of records and record sets (Results/ResultSets in DBIC parlance) split nicely and each encapsulates the proper layers like engine and SQL generation. These things have steep learning curves but once you get the hang of them they make dealing with data and databases trivial, testable, flexible, perly, and largely self-documenting [citation needed].

Re: Why use an OO -> SQL mapper module?
by Your Mother (Archbishop) on Aug 12, 2011 at 00:31 UTC

      Chained result sets are immensely useful. Certainly I could write the necessary SQL by hand, but chaining result sets mean that I don't have to!

Re: Why use an OO -> SQL mapper module?
by duelafn (Parson) on Aug 11, 2011 at 19:26 UTC

    "what benefit there is to replacing the conciseness of a SQL statement (which can be wrapped up into a method anyways, right?)"

    Indeed - my take on it is that these ORMs are (at one level) just the generalization of those methods written (and tested) for you already.

    You also end up with some nice tricks that other people found useful like DBIx::Class's ResultSets which are nice for building up a query over different chunks of code:

    my $store = $schema->resultset('Items'); $store = restrict_to_department( $store, $department ) if $department; $store = restrict_to_seller( $store, $seller ) if $seller; print format_top_ten_items( $store ); # doesn't care whether $store is + restricted sub restrict_to_department { $_[0]->search({ 'department.name' => $_[1] }, { join => "departments +" }); }

    I doubt hand-rolled code could be so concise (without re-implementing DBIx::Class). the restrict_to* subs are completely independent (don't even care whether the other feature exists). The database won't be hit until $store is iterated over within the call to format_top_ten_items. Of course - you do have the investment in learning the ORM (which is non-trivial) and, as always, the benefit to your application may vary. I was once a skeptic, but have decided that for most code (simple imports/exports being the most obvious exception), an ORM (DBIx::Class in particular) is worth the investment to learn and use.

    Good Day,
        Dean

Re: Why use an OO -> SQL mapper module?
by jethro (Monsignor) on Aug 11, 2011 at 17:49 UTC

    One advantage immediately comes to (my) mind: You don't neccesarily need to know SQL

    As I can see, Class::DBI mentions two further advantages in its Introduction section

      One advantage immediately comes to (my) mind: You don't neccesarily need to know SQL
      Hmmm. There's no reason not knowing SQL means you have to use an OO mapper. Furthermore, taking Class::DBI as an example, it only generates basic SQL for you. Anything a little bit non-trivial, you need to come up with yourself.
      Class::DBI mentions two further advantages in its Introduction section
      Eh, the "let's reinvent the wheel" section when it comes to triggers and such? You call that an advantage?

      I find that Class::DBI doesn't abstract. Quite the opposite. By mapping tables to classes, it exposes the structure of your database to your application.

        There's no reason not knowing SQL means you have to use an OO mapper.

        No, there is no reason to use OO if you want to abstract, but it is a possibility. And the original question was why should someone substitute SQL with OO.

        Furthermore, taking Class::DBI as an example, it only generates basic SQL for you. Anything a little bit non-trivial, you need to come up with yourself.

        If someone doesn't know SQL what are the chances that he will generate non-trivial SQL?

        I find that Class::DBI doesn't abstract. Quite the opposite. By mapping tables to classes, it exposes the structure of your database to your application.

        I don't have a problem with calling the abstraction a mapping instead. Note that the author himself says that Class::DBI "provides a *simple* database to object *mapping* layer" (emphasis added). The two advantages he mentions (higher oder functions usable without database having a say in it and abstraction of database implementation) still seem to hold even though they might not be implemented to everyones satisfaction

Re: Why use an OO -> SQL mapper module?
by locked_user sundialsvc4 (Abbot) on Aug 11, 2011 at 20:44 UTC

    I find them to be generally useful, albeit with one very important (to me...) caveat:   they are not the basis of “my program’s objects.”

    For program-construction purposes, I think of “objects” as “Things.™”   Those are the Things™ which pop up in ordinary business context discussions about what the program is supposed to be doing for the business that is paying for it.   It is inevitably true that those Things™ will be instantiated using information from one or more database tables, but that is an opaque characteristic of the Thing™ from a business point-of-view ... therefore, the object’s implementation conceals it.   OO-wrappers may well be used in the employed in the implementation of the CRUD methods of the Thing™, but, in my designs, none of these subordinate objects are “the Thing™ itself.”

    Actually, I do find that OO-wrappers are actually quite handy, because when you start using them in earnest, you really do discover just how much of your time you’ve been spending all these years, dicking around with the construction of SQL strings . . .

Re: Why use an OO -> SQL mapper module?
by jdrago999 (Pilgrim) on Aug 15, 2011 at 03:20 UTC

    Class::DBI::Lite FTW!!!

    Seriously though - to answer your question - "Why?" - it comes down to a matter of preference. I prefer to deal with objects when possible - but not at any cost.

    If you simply want to loop over the items in your table and do a string substitution on one of their fields, you can setup a "select" statement handle and an "update" statement handle, iterate over the results of your "select" and execute the "update" handle once for each item. Or....

    foreach my $widget ( My::db::widget->search_where({foo => 'bar'}) ) { (my $value = $widget->frob) =~ s{blech}{blargh}sig; $widget->frob($value); $widget->update; }

    Easier to write and easier to follow 4 lines of code than a dozen or more...