[Dbix-class] prefetch across multiple tables

John Stoffel john at stoffel.org
Wed Dec 17 03:56:11 GMT 2014


Hi,

I've been pounding my head trying to figure out what I'm doing wrong
here.  I've got a simple three table DB:

Names: full_name, name_id   
has_many:
  Account: account_id, boxfolder_id, URL, comment
    has_one:
      Boxfolder:  boxfolder_id, volume, folder, range

I can do simple SQL queries, looking for full_name like this:

mysql> SELECT n.name_id,n.full_name,a.account_id,b.boxfolder_id,b.volume,b.folder,b.range FROM names as n LEFT JOIN account AS a ON n.name_id = a.name_id LEFT JOIN boxfolder AS b on a.boxfolder_id = b.boxfolder_id WHERE n.full_name LIKE 'Emlen%';
+---------+----------------+------------+--------------+--------+--------+-----------+
| name_id | full_name      | account_id | boxfolder_id | volume | folder | range     |
+---------+----------------+------------+--------------+--------+--------+-----------+
|    8213 | Emlen & Howell |       5920 |          234 | 24     | 10     | 2237-2266 |
|    8213 | Emlen & Howell |       5921 |          249 | 26     | 10     | 2792-2823 |
|    8213 | Emlen & Howell |       5922 |          281 | 28     | 12     | 4022-4063 |
|    8214 | Emlen, Caleb   |       5923 |           14 | 2      | 14     | 322-347   |
|    8214 | Emlen, Caleb   |       5924 |           50 | 6      | 5      | 2035-2082 |
+---------+----------------+------------+--------------+--------+--------+-----------+
5 rows in set (0.00 sec)


Now when I try to use DBIx::Class (inside a Dancer web app) I just
can't make it work.  My code looks like this:

#!/usr/bin/perl -w
use DBIx::Class;
use lib '../lib';
use Carey::Schema;
use Data::Dumper;

my $name = shift @ARGV;
$name .= "%";

my $schema = Carey::Schema->connect('DBI:mysql:database=foo;host=localhost;port=3306', 'password','', { PrintError => 1, RaiseError => 1});

my $rs = $schema->resultset('Name')->search({ full_name => { like => $name }, },
                                            { limit => 10,
                                              order_by => { -asc => 'full_name' },
                                              prefetch => [ 'account', { 'account' => 'boxfolder'}],
                                            });

while (my $r = $rs->next) {
  print "Full Name: ", $r->full_name, " (", $r->name_id, ")\n";

  foreach my $a ($r->account()) {
    print "Account: ", $a->account_id();
    print "  (boxfolder_id: ", $a->get_column('boxfolder_id'), ") ";
    my $t = $a->url();
    $t =~ m/value2=(\w+)\&/;
    print "  URL: $1\n";
    $vol = $a->boxfolder()->volume;
    print "VOL: $vol\n";
    print "\n";
  }
}


And in the various schemas, generated with dbicdump, I have stuff like this:

Name.pm:
__PACKAGE__->has_many('account', 'Carey::Schema::Result::Account','name_id');

Account.pm:
__PACKAGE__->belongs_to('name', 'Carey::Schema::Result::Name','account_id');
__PACKAGE__->has_one('boxfolder', 'Carey::Schema::Result::Boxfolder','boxfolder_id' );

Boxfolder.pm:
__PACKAGE__->belongs_to('account','Carey::Schema::Result::Account','boxfolder_id');



Now when I run the above code, looking for a name like "Emlen" (don't ask!  It's not my data... :-)

I get stuff like this:

> ../bin/dbic-test.pl Emlen
DBIx::Class::ResultSet::next(): Prefetching multiple has_many rels account and account at top level will explode the number of row objects retrievable via ->next or ->all. Use at your own risk. at ../bin/dbic-test.pl line 19
Full Name: Emlen & Howell (8213)
Account: 5920  (boxfolder_id: 234)   URL: b16f10
Can't call method "volume" on an undefined value at ../bin/dbic-test.pl line 28.


I've tried multiple variations of the prefetch, like:

   prefetch => { 'account' => 'boxfolder' }
   prefetch => [ 'account', 'boxfolder' }

but I'm missing something, even though I've been reading and
re-reading the DBIx::Class::Manual::Cookbook back and forth and trying
to wrap my brain around what I'm missing.

What am I missing?

Thanks,
John



More information about the DBIx-Class mailing list