Re: Hibernate and ActiveRecord (Ruby-on-Rails) comparison

[prev] [thread] [next] [Date index for 2005/04/05]

From: Michael Graham
Subject: Re: Hibernate and ActiveRecord (Ruby-on-Rails) comparison
Date: 00:32 on 05 Apr 2005
Thanks for the review of the review, Tony!

> That said, one of the things I'd like to see in CDBI is a way to inflate
> several classes simultaneously from an actual join. It shouldn't be too
> hard to do - I've just never needed it yet enough to write the code
> rather than just inlining some SQL.


I took a stab at this a couple of weeks ago.  But I solved my specific
dayjob issue, so coding the general-purpose module got lower on my todo
list.

My approach was to use 'construct' to store lists of related objects in
the has_many field:

     my $cd = Music::CD->construct({
         cdid     => 7,
         artist   => 3,
         title    => 'Mule Variations',
         year     => '1999',
         tracks   => \@list_of_tracks;
     });

And also to change the has_many relationship from 'tracks' to
'retrieve_tracks':

     Music::CD->has_many(retrieve_tracks => 'Music::Track');

Then you create a method in Music::CD called 'tracks' that returns the
pre-constructed value if it is availble:

     sub tracks {
         my $self = shift;
         if (exists $self->{'tracks'} and ref $self->{'tracks'} eq 'ARRAY') {
             return @{ $self->{'tracks'} } if wantarray;
             return Class::DBI::Iterator->new(
                 'Music::Track',
                 $self->{'tracks'},
             );
         }
         else {
             return $self->retrieve_tracks;
         }
     }


(And then of course there's the method that actually populates CDs and
Tracks from a single query, but that part is not too difficult.)

Advantages of this approach:
 - don't have to modify CDBI::Relationship::HasMany or create a new
   relationship class that respects the pre-constructed value in
   $self->{'tracks'}

Disadvantages of this approach:
 - the user has to remember to call 'retrieve_tracks' if they don't want
   the cached version


The caching here is pretty nasty, because basically, it never expires
until you destroy the object or call retrieve_tracks again.  

Of course there's nothing saying the system can't be configured to do
this instead:

    Music::CD->has_many(tracks => 'Music::Track');

    sub joined_tracks {
        my $self = shift;
        if (exists $self->{'tracks'} and ref $self->{'tracks'} eq 'ARRAY') {
            return @{ $self->{'tracks'} } if wantarray;
            return Class::DBI::Iterator->new(
                'Music::Track',
                $self->{'tracks'},
            );
        }
        else {
            return $self->tracks;
        }
    }


This is clearly much safer, but then it isn't really transparent, is it?

Any feedback on the design of this would be appreciated.


Michael


--
Michael Graham <magog@xxxxxxxx.xxx>


Re: Hibernate and ActiveRecord (Ruby-on-Rails) comparison
Michael Graham 00:32 on 05 Apr 2005

Generated at 09:29 on 27 Apr 2005 by mariachi v0.52