Perl:DBIx :: Class Beginner - 子集关系和预取

时间:2013-06-04 22:57:26

标签: sql database perl orm dbix-class

好的,我是DBIx :: Class的新手。我有一对多的关系设置,如下:

User -> has_many -> Addresses

好的,好的。我可以进行查询,并将其称为预取JOINed表,如下所示:

Foo::DBIC->storage->debug(1);    # output SQL to STDOUT

my $user = Foo::DBIC->resultset('Users')->search({}, {
  prefetch => [ 'addresses' ],
  join     => [ 'addresses' ],
  rows     => 1
})->single;

for my $address ($user->addresses->all) {
  say $address->zip_code;
}

两个表,一个SQL查询(通过调试验证)。一切都很好。

然而,现在,假设我想在Foo :: DBIC :: Result :: Users中编写一个或两个重载方法,根据某些条件返回地址的子集。这是我添加到Users类的内容:

sub home_addresses {
  my $self = shift;

  return $self->search_related('addresses', { address_type => 'home' });
}

sub business_addresses {
  my $self = shift;

  return $self->search_related('addresses', { address_type => 'business' });
}

我可以像这样调用这些重载,它们可以工作:

for my $address ($user->home_addresses->all) {
  say $address->zip_code;
}

然而,这个忽略这个事实,我已经预取了我的连接,它执行了额外的查询(好像我没有预取并加入任何东西)。

所以,我的问题是:如何定义一个返回相关表子集的重载方法,但是使用已经预取的连接? (只需在预取中添加WHERE子句)...

我的问题是,如果我有很多重载方法返回相关的表子集,我的查询计数会爆炸;特别是如果我在一个循环中调用它们。

我有理由这样做,当然是丑陋的。我的现实生活模式比用户和地址更多,很多,很多,而且我试图尽可能地抽象出丑陋。

谢谢!

2 个答案:

答案 0 :(得分:0)

对于home_addresses来说,这样的事情可能有用:

sub home_addresses {
  my $self = shift;
  my $addresses = $self->addresses;
  my $home_addresses;
  while (my $row = $addresses->next()) {
    push @$home_addresses, $row if $row->address_type() eq 'home';
  }
  my $home_rs = $addresses->result_source->resultset;
  $home_rs->set_cache( $home_addresses );
  $home_rs;
}

或者,如果有很多类似的地址类型:

sub addresses_by_type {
  my $self = shift;
  my $addresses = $self->addresses;
  my $type;
  my $rs_type;
  while (my $row = $addresses->next()) {
    push @{$type->{"".$row->address_type}},
        $row;
  }
  for (keys %$type) {
    my $new_rs = $addresses->result_source->resultset;
    $new_rs->set_cache( $type->{$_} );
    $rs_type->{$_} = $new_rs
  }
  return $rs_type  
}

您可以通过以下方式访问“主页”地址:

while (my $r = $user->next) {
  use Data::Dumper;
  local $Data::Dumper::Maxdepth = 2;
  print $r->username,"\n";
  my $d = $r->addresses_by_type();
  my $a = $d->{home};
  while (defined $a and my $ar = $a->next) {
    print $ar->address,"\n";
  }
}

答案 1 :(得分:-1)

你可以尝试这样的事情:

sub home_addresses {
  my $self = shift;
  my $return = [];
  my @addresses = $self->addresses->all();
  foreach my $row (@addresses) {
    push @$return, $row if $row->address_type() eq 'home';
  }

  return $return;
}