블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2008.08.06 19:42

[ Perl ] Perl 에서의 ORM , DBIx::Class에 대해서... #4 - Relation


 자, 그럼 Relation 에 대한 이야기입니다.

 Relation 은 말그대로 관계입니다. 뭐에 대한 관계냐면, Schema Class 간의 관계이죠.
 
 User, Company, Deathnote 에서 Deathnote 는 User 의 user_id 와 Company 의 company_id 를 가지고 있습니다.
 그럼 어떻게 Deathnote 에서 User 의 name 을 알 수 있을까요?
 ( SQL 스럽게 하면 애들장난같은 얘기라서 접어두겠습니다만 )

  아, 그전에 일단 테스트 용으로 데이터를 집어넣겠습니다.

my $deathnote = $schema->resultset('Deathnote');

while(<DATA>) {
    chomp;
    my @data = split/,/, $_;
    $deathnote->create({
        user_id => $data[0],
        company_id => $data[1],
    });
}

__DATA__
1,1
2,2
3,3
4,4
5,5
6,6
7,7

  자.. 어떻게 할 것인가... 가장 간편하게 이런 방법이 있습니다.
my $deathnote = $schema->resultset('Deathnote')->search({});

while(my $row = $deathnote->next) {

    my $user = $schema->resultset('User')->find($row->user_id);
    print $user->name if $user;
}
 흠? 근데 이건 좀 너무하다 싶지 않나요?

 이렇게 생각하면 Relation 이 나올 때입니다.
 MyTest/Deathnote.pm 을 보겠습니다. 아, 다른 건 다 집어치우고... 그냥 추가된 것만 보죠.

__PACKAGE__->has_one( user => 'MyTest::User', { 'foreign.user_id' => 'self.user_id' } );
__PACKAGE__->has_one( company => 'MyTest::Company', { 'foreign.company_id' => 'self.user_id'
} );

 이렇게 추가했습니다.
  Deathnote 에서 User 로 연결하기 위해서 user 라는 키를 사용하고,
User 와 Deathnote 는  user_id 로 연결된다는 내용입니다. (has_one 이라는 것은 말 그대로 1:1의 관계입니다)
  그리고 Company 역시나 마찬가지입니다.
  이렇게 Relation 을 지정해두면 어떻게 되려나요?

 my $deathnote = $schema->resultset('Deathnote')->search({});

while(my $row = $deathnote->next) {
  print $row->user->name."¥n";
}

  이런 형식으로 간단하게 user의 name 을 얻어올 수 있습니다.
.
.
.
  정말로 그럴까요? 두번째 장에서 하얀_고양이라는 User 를 삭제했기 때문에 세번째 Deathnote 에서는 에러가 발생합니다.

  can't call method "name" on an undefined value at ..

 그러면 이렇게 해주면 됩니다. user 가 있으면 찍어라 라고...

   print $row->user->name if $row->user;

  간단하죠;;;

 근데 User 가 어떤 Company 인지를 알고 싶습니다. 근데 이 정보는 Deathnote 에만 있어요.
 User->Deathnote->Company 식으로 넘어가야되는데요...

  우선은 MyTest/User.pm 을 열어서 한 줄 추가합니다.

__PACKAGE__->belongs_to( note => 'MyTest::Deathnote', { 'foreign.user_id' => 'self.user_id' });

  belongs_to 라는 것은 말 그대로입니다. :-) Deathnote 에 User 가 has_one 으로 Relation 관계를 성립하고 있습니다. belongs_to 로 Deathnote 에 속하게 됩니다. (근데 has_one 으로도 Relation 관계가 성립되더군요;;; 뭔가 일방적인 관계일지도..)

  그러면 User 에서 Company 의 name  을 읽어 볼까요?

my $user = $schema->resultset('User')->search({});

while(my $row = $user->next) {
   
    print $row->name .'=>'.$row->note->company->name."\n" if $row->note && $row->note->company;

}

  이렇게 하면 되겠죠?

  근데 여기서 잠깐... "언제까지 전체 레코드를 읽어올 것인가요. 제대로 SQL 조건도 좀 주고.. 이러고 싶은데.." 라고 saillinux 님께서 사장님 마인드로 또 말씀하십니다.

  그러면서 던져주신 조건이란게 << user_id 가 3 을 넘고, company_id 가 2 를 넘는 것 >> 이라고 하네요.
 근데 User Schema Class 를 사용하라고 합니다. 어라... 분명 User Schema Class 에는 company_id 가 없는 데 말이죠. 역시 사장님 마인드입니다.

  "거기다가 company_id 순으로 정렬하고, 그 중에 딱 2개만 보고 싶어요" 라고 하시는 군요...
  오늘 제대로 뽕을 뽑으시는 군요.

   요건 정의를 다시 해보겠습니다.

    "user_id" 가 3 을 넘고,
    "company_id"  가 2 를 넘고,
    "User" Schema Class 를 사용하고,
    "company_id" 순으로 정렬하고
    "2개" 만 출력한다 입니다.
.
.
.
.
  답은 이렇습니다.  

my $user = $schema->resultset('User')->search({
    'me.user_id' => { '>' => 3 },
    'company.company_id' => { '>' => 2 },
},{
    prefetch => [ { 'note' => 'company' } ], 
    order_by => 'company.company_id asc',
    rows => 2,
});

while(my $row = $user->next) {
    print $row->name. '=>' .$row->note->company->name."\n";
}

  User Schema Class 에서 Company 와는 어떤 관계도 아닙니다. 그럴려면 Deathnote 를 통해서 Company 에 접근할 수 있습니다.
 
   prefetch => [ { 'note' => 'company' } ]

  MyTest::User 에서 note 로 Deathnote 에 갈 수 있고, Deathnote 는 company 로 Company에 접근할 수 있습니다.  Relation 관계는 이미 Schema Class 에서 정의해줬기 때문에 이렇게 간단하게 접근할 수 있습니다.

    order_by => 'company.company_id asc',

  company_id 순이라면 위의 prefetch 에서 이미 길을 텄기때문에 "company.company_id"  로 접근할 수 있습니다.(SQL::Abstract 를 참조하세요)
 
      rows => 2

  단 두줄만 뺀다는 겁니다. MySQL 의 LIMIT 2 같은 사용법이죠.

  물론 Relation은 might_have, has_many 같은 것들도 있습니다. 자세한 내용은 문서를 참조하세요. :-)

  이런저런 빼고 넘어가는 부분들이 많은지라... 조금만 문서를 보시면 금방 아실만한 내용들이 대부분일 겁니다. 모르시면 같이 한번 궁리해보죠 :-)

  흡.. 빠진 부분들(제가 아는 한도에서)은 다음에 DBIC 를 정리하는 차원에서 가볍게 짚고 가도록 하겠습니다.


신고
TOTAL 483,668 TODAY 7

티스토리 툴바