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

I'm working on a project using some Perl classes (regular hash-based objects) as well as some MySQL database tables, where the two often mirror each other. I'm hoping for some feedback from those here in the Monastery on proper ways to handle the relationship between the classes and the tables.

What classes do I make my tables from?

For now, my tables are named after the classes at the bottom of my inheritance hierarchy. For example, given the 4 classes:

Car FastCar Cadillac NashRambler

the db tables for that would be "cadillacs" and "nash_ramblers".

One thing I immediately notice though is that the two tables have a lot of duplication (ex., both classes inherit their flux_capacitor_present instance attribute from FastCar, and so each have a flux_capacitor_present field in their respective db tables). Should there be a fast_cars table, where the cadillacs and nash_ramblers tables would each have fast_car_id fields holding foreign keys?

Is there a general rule you might recommend for how to estimate how much to abstract, and how much db duplication to allow? How closely should your db table layout follow your class layout?

Lots of repetitive code for creating objects from tables

The other thing I'm finding myself doing is writing a lot of code to extract data from a db table to build my objects. For example:

# Inside the Garage class, which will contain a list of Nash Ramblers. +.. # Get info on some of them that the garage cares about. my $query = 'select owner, mileage, color, ... from nash_ramblers ...' +; my $result_ref = $dbh->selectall_arrayref( ... ); $self->{nash_ramblers} = []; # Store the list in this instance attribu +te. for ( @{$result_ref} ) { my $a_ref = $_; my $car_ref = NashRambler->new(); $car_ref->set_owner( $a_ref->[0] ); $car_ref->set_mileage( $a_ref->[1] ); $car_ref->set_color( $a_ref->[2] ); # ... snip a bunch of similar setter calls ... push @{ $self->{nash_ramblers} }, $car_ref; } # Ok, now for the Cadillacs...

The Garage constructor has a lot of that sort of thing to generate the lists of objects it contains. Is there a common Perl idiom folks use to avoid that sort of repetition?

Thanks.

Replies are listed 'Best First'.
Re: Design help: OO Perl and db tables
by CountZero (Bishop) on Jan 01, 2007 at 09:16 UTC
    It looks like you really could do with some module like DBIx::Class which is all about linking objects to database-tables, records, relationships, ... etc. Have a look at it, it seems overwhelming at first, but once you are into it, you never will go back to "pure" DBI. There is a very lively and responsive community of designers and users working on it (all info in the docs!).

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Design help: OO Perl and db tables
by jettero (Monsignor) on Jan 01, 2007 at 13:16 UTC

    I've been meaning to look at DBomb since it came up in SoPW a while back. It has a silly name, but it looked pretty slick nonetheless. It appears to be a different approach that does the same thing as DBIx::Class above.

    -Paul

Re: Design help: OO Perl and db tables
by EdwardG (Vicar) on Jan 02, 2007 at 09:30 UTC

    Is there a general rule you might recommend for how to estimate how much to abstract, and how much db duplication to allow?

    I recommend avoiding duplication. If you allow duplication, then you also allow the possibility that two or more pieces of information will be in conflict with each other, also known as data corruption. There are ways to mitigate this risk, but none are as effective as disallowing duplication altogether.

    There's no absolute correct answer to the right level of abstraction. It depends on how the system will be used, considering performance, scalability, maintenance, and quality requirements. Compare for example OLTP and OLAP. It might help to think of your object model as a representation of your data suited to the functional requirements of your application or interface, whereas your database model should be designed to suit non-functional requirements such as data integrity and maximising query flexibility.

     

      It might help to think of your object model as a representation of your data suited to the functional requirements of your application or interface, whereas your database model should be designed to suit non-functional requirements such as data integrity and maximising query flexibility.

      Thanks Edward. That sounds like it makes a lot of sense. I think that angle is what I was missing. :)

Re: Design help: OO Perl and db tables
by Moron (Curate) on Jan 02, 2007 at 10:42 UTC
    The usual OO way to avoid such repetition is to have a more abstracted container class (say CarContainer) from which the Garage and the Cadillac inherit their common functionality.

    -M

    Free your mind

      Right -- and I think my class hierarchy does a good job of keeping common qualities in base classes. For example, Car might have a get_transmission_type method, since that's common to all cars. FastCar might have a get_turbo_type method, since, in my limited world, only fast cars have turbos. :)

      But now, in my cadillacs and nash_ramblers database tables, do I put string fields/columns in *both* of those tables for transmission_type and turbo_type? Or is it more customary to create a transmission_types table, and a turbo_types table, and have foreign keys in the cadillacs and nash_ramblers tables that refer to those other tables? What if there's only 4 different transmission types? What if one car has an "UltraSpin" turbo and another has an "Ultra-spin" one?

      Continuing, my two fast cars have an awful lot in common with each other (corresponding to all the attributes they inherit from FastCar and Car). So, at some point, you can go overboard in pulling out every little attribute into its own table. You could end up with cadillacs and nash_ramblers full of almost nothing but foreign keys. (Hm... well, items with floating values, like fuel_level (no pun intended) would still be a regular value and not a foreign key...)

      I'm starting to think that the common practice might be to use the classes at the bottom of your inheritance hierarchy as models for your db tables, and *then* pull out common data into its own tables when it ``makes sense to do so''. I'd be curious to hear if this is what other folks do, and if they have any rules of thumb about how to figure when it makes sense to pull data out into a new table.

      Edit: After re-reading Edward's advice (above), I see that, in the above example, even though you might only have a handful of transmission types, you probably still would want to have a table for them, rather than putting lots of strings in your tables for something that would fit nicely into an additional table (same goes for turbo types). Thank you.

Re: Design help: OO Perl and db tables
by Raster Burn (Beadle) on Jan 02, 2007 at 16:38 UTC
    While DBIx::Class and Rose::DB::Object are good ORM systems, I think the OP is asking about how to handle inheritance in an ORM system, and it's a question that I often wonder about too. How does an ORM support sub-classing?
      Most ORM's reflect fairly close the table-structure of the database they are linked with. As such there is no sub-classing in the sense you mean, other than what follows out of primary and foreign key relationships.

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law