2014-10-08 55 views
1

給定一個數據庫架構這樣導航關係和進一步約束結果集與查詢

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小號進一步制約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>)

注意,我知道我卡恩指定調用查詢到orgunitaccounts(),但只作用範圍是orgunitaccount表,而我想約束的基礎上account一個屬性集。

+0

請粘貼DBIx :: Class結果資源而不是DDL語句,這樣可以更容易地爲您提供幫助。你也應該使用find而不是search來獲取單行,在你的情況下,通過爲number列定義一個唯一的約束並使用它。 – 2014-10-08 10:12:17

+0

我知道,我可以使用find來獲得單個結果,但這不是我的問題的關鍵。 ;)結果來源有點渺茫......但我會盡我所能。 – sschober 2014-10-08 10:54:12

回答

0

一般來說,您希望在ResultSet上調用您想要獲取Result對象的搜索,在您的情況下似乎是Orgunits。如果您有帳戶對象已經爲你不需要加入accountid但搜索orgunitaccounts.accountid => $account,而不是其他一些原因

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

: 那麼,爲什麼不這樣做。

另一種可能性是使用search_related。

+0

啊,所以它歸結爲根本不使用導航方法,而是使用連接。現在閱讀加入語法,謝謝! – sschober 2014-10-10 09:48:46

+0

爲了完整起見,我在解決方案分支的示例項目中[已實施](https://github.com/sschober/dbix-rel-navigation-and-query/tree/solution)您的建議。 – sschober 2014-10-10 10:04:11

+0

太棒了,但請不要將DBIX作爲DBIx :: Class的首字母縮寫。這是一個完整的命名空間,其中有很多其他項目存在。常用的縮寫是DBIC。 – 2014-10-10 14:40:13