2014-10-08 5 views
1

Учитывая дб схемы, как этотNavigate отношения и далее результат Ограничить набор с запросом

create table account (
id  serial primary key, 
no  varchar 
); 
create type sourcetype as enum ('TYPE_A','TYPE_B'); 
create table orgunit (
id  serial primary key, 
name varchar, 
source sourcetype 
); 
-- N:M-Relationship between Accounts and OrgUnits 
create table orgunitaccount (
orgunitid int references orgunit(id), 
accountid int references account(id) 
); 

Использование dbicdump по этой схеме приводит к следующим классам (обратите внимание, что я вырезал комментарии):

use utf8; 
package RelTest::Result::Account; 
use strict; 
use warnings; 
use base 'DBIx::Class::Core'; 
__PACKAGE__->table("account"); 
__PACKAGE__->add_columns(
    "id", 
    { 
    data_type   => "integer", 
    is_auto_increment => 1, 
    is_nullable  => 0, 
    sequence   => "account_id_seq", 
    }, 
    "no", 
    { 
    data_type => "text", 
    is_nullable => 1, 
    original => { data_type => "varchar" }, 
    }, 
); 
__PACKAGE__->set_primary_key("id"); 
__PACKAGE__->has_many(
    "orgunitaccounts", 
    "RelTest::Result::Orgunitaccount", 
    { "foreign.accountid" => "self.id" }, 
    { cascade_copy => 0, cascade_delete => 0 }, 
); 
1; 

use utf8; 
package RelTest::Result::Orgunit; 
__PACKAGE__->table("orgunit"); 
__PACKAGE__->add_columns(
    "id", 
    { 
    data_type   => "integer", 
    is_auto_increment => 1, 
    is_nullable  => 0, 
    sequence   => "orgunit_id_seq", 
    }, 
    "name", 
    { 
    data_type => "text", 
    is_nullable => 1, 
    original => { data_type => "varchar" }, 
    }, 
    "source", 
    { 
    data_type => "enum", 
    extra => { custom_type_name => "sourcetype", list => ["TYPE_A", "TYPE_B"] }, 
    is_nullable => 1, 
    }, 
); 
__PACKAGE__->set_primary_key("id"); 
__PACKAGE__->has_many(
    "orgunitaccounts", 
    "RelTest::Result::Orgunitaccount", 
    { "foreign.orgunitid" => "self.id" }, 
    { cascade_copy => 0, cascade_delete => 0 }, 
); 
1; 

use utf8; 
package RelTest::Result::Orgunitaccount; 
__PACKAGE__->table("orgunitaccount"); 
__PACKAGE__->add_columns(
    "orgunitid", 
    { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, 
    "accountid", 
    { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, 
); 
__PACKAGE__->belongs_to(
    "accountid", 
    "RelTest::Result::Account", 
    { id => "accountid" }, 
    { 
    is_deferrable => 0, 
    join_type  => "LEFT", 
    on_delete  => "NO ACTION", 
    on_update  => "NO ACTION", 
    }, 
); 
__PACKAGE__->belongs_to(
    "orgunitid", 
    "RelTest::Result::Orgunit", 
    { id => "orgunitid" }, 
    { 
    is_deferrable => 0, 
    join_type  => "LEFT", 
    on_delete  => "NO ACTION", 
    on_update  => "NO ACTION", 
    }, 
); 
1; 

Полный код примера в this github репозиторий.

Я ищу способ навигации этого отношения, начиная с account к набору orgunit s далее ограничивающего который orgunit сек я хочу, чтобы выбрать, основе атрибуты целевой таблицы (account). Мой текущий подход заключается в следующем:

my $schema = $schemaPkg->connect(...); # not important 
my $account = 
    $schema->resultset('Account')->search(number => $acctNumber)->single(); 
my $typeBAccounts = 
    grep { $_->orgunitid->source eq 'TYPE_B'} 
    $account->orgunitaccounts(); 

Мой вопрос: Есть ли способ, чтобы включить это ограничение в навигационных команд, как с search(<queryHashRef>)?

Обратите внимание, что я знаю, что я Cann указать запрос в вызове orgunitaccounts(), но это видимость только в orgunitaccount таблицы, в то время как я хочу, чтобы ограничить набор на основе атрибуте account.

+0

Пожалуйста, вставьте источники данных DBIx :: Class вместо операторов DDL, чтобы вам было легче помочь. Вы также должны использовать поиск вместо поиска, если хотите получить одну строку, в вашем случае, определив уникальное ограничение для столбца номера и используя это. –

+0

Я знаю, я могу использовать find для получения единственного результата, но это не вопрос моего вопроса. ;) Источники данных немного лонигш ... но я сделаю все возможное. – sschober

ответ

0

Как правило, вы хотите вызвать поиск на ResultSet, из которого вы хотите получить объекты результатов, в вашем случае, который кажется Orgunits. Так почему бы не сделать что-то вроде:

my $rs_orgunits = $schema->resultset('Orgunit')->search({ 
     source => 'TYPE_B', 
     'accountid.number' => $acctNumber, 
    }, 
    { 
     join => { orgunitaccounts => 'acountid' }, 
    }); 

Если у вас есть объект учетной записи уже по какой-то другой причине, вы не должны присоединиться к accountid но искать orgunitaccounts.accountid => $account вместо этого.

Другая возможность - использовать search_related.

+0

А, так это сводится к тому, что вообще не используются навигационные методы, но с использованием объединений. Прочитав синтаксис соединения прямо сейчас, спасибо! – sschober

+0

Просто для полноты я внедрил (https://github.com/sschober/dbix-rel-navigation-and-query/tree/solution) ваше предложение в своем примере проекта на ветке решения. – sschober

+0

Отлично, но, пожалуйста, не используйте DBIX в качестве сокращения для DBIx :: Class. Это полное пространство имен, в котором существует множество других проектов. Общая аббревиатура - DBIC. –