2

好的,我是 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 中编写一个或两个重载方法,根据某些标准返回地址子集。这是我添加到用户类的内容:

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 子句附加到预取)...

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

我这样做的理由当然是丑陋的。我的现实生活模式比用户和地址要混乱很多很多,我正在尽我所能抽象出丑陋的东西。

谢谢!

4

2 回答 2

0

something like this for home_addresses might work:

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;
}

Alternatively, if there a lot of address types something like this:

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  
}

which you could access the 'home' addresses from like this:

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";
  }
}
于 2013-06-05T04:32:45.443 回答
-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;
}
于 2013-06-05T02:16:09.043 回答