2013-06-04 4 views
2

Хорошо, я новичок в DBIx :: Class. У меня есть отношения «один ко многим», например:Perl: DBIx :: Class Beginner - Отношения для подмножества и предварительная выборка

User -> has_many -> Addresses 

Хорошо, хорошо. Я могу сделать запрос, и вызвать его предварительную выборку соединяемых таблиц, например, так:

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 к предварительной выборке) ...

Моя проблема в том, что если у меня много перегруженных методов, возвращающих связанные подмножества таблиц, мой счетчик запросов может взорваться; особенно если я вызываю их из цикла.

У меня есть причины для этого, которые, конечно, уродливые. Моя реальная схема жизни много, много, много грязнее, чем пользователи и адреса, и я стараюсь абстрагироваться от уродливых, насколько это возможно.

Спасибо!

+0

Поскольку вы не хотите повторно запрашивать базу данных, почему вы вызываете методы DBIC? Вы не получите никаких преимуществ в отношении запросов, просто напишите методы, которые фильтруют возвращаемые данные с помощью функций perl (например, grep). – MkV

+0

Интересно, почему вы называете их перегруженными методами? Перегрузка в Perl - это когда вы, например, определяете, какой объект должен возвращаться в числовом контексте. –

+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"; 
    } 
} 
+0

Это сделало трюк. Спасибо! –

+0

@MkV С момента обращения к result_source-> resultset на $ address ($ self-> addresses) будет возникать побочный эффект изменения $ self-> адресов? – melutovich

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

Вам не нужно сначала присваивать $ self-> адреса временному, чтобы он не зацикливался навсегда? В основном он будет продолжать получать первую запись из таблицы объединенных адресов на каждой итерации цикла. вместо * my $ ar = $ self-> адресов; while (my $ row = $ ar-> next()) {* – MkV

+0

Вы верны.Я обновил sub для использования -> все. – user353255

+0

Это было близко, но ответ MkV выше возвращает ResultSet со всеми методами, которые идут с ним. Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^