2

わかりました、DBIx::Class は初めてです。次のように、1対多の関係が設定されています。

User -> has_many -> Addresses

わかりました。次のように、クエリを実行して、JOIN されたテーブルのプリフェッチと呼ぶことができます。

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

2 つのテーブル、1 つの SQL クエリ (デバッグで検証)。すべては順調です。

しかしここで、Foo::DBIC::Result::Users に、特定の基準に基づいてアドレスのサブセットを返すオーバーロード メソッドを 1 つまたは 2 つ書きたいとします。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;
}

ただし、これは結合をプリフェッチしたという事実を無視し、ADDITIONAL QUERIES を実行します (何もプリフェッチして結合していないかのように)。

そこで、私の質問は次のとおりです。関連テーブルのサブセットを返すが、既にプリフェッチされた結合を使用するオーバーロード メソッドを定義するにはどうすればよいですか? (プリフェッチに WHERE 句を追加するだけです)...

私の問題は、関連するテーブルのサブセットを返すオーバーロードされたメソッドが多数ある場合、クエリ数が急増する可能性があることです。特にループ内から呼び出している場合。

もちろん、これを行うには醜い理由があります。私の実際のスキーマは、Users や Addresses よりもずっと、ずっと、ずっと、ぐちゃぐちゃです。

ありがとう!

4

2 に答える 2

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";
  }
}
于 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 に答える