Re: Hibernate and ActiveRecord (Ruby-on-Rails) comparison
[prev]
[thread]
[next]
[Date index for 2005/04/05]
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>