SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
1.
DBIx::Class (aka DBIC)
for (advanced) beginners
Leo Lapworth @ LPW 2008
http://leo.cuckoo.org/projects/
2.
assumptions
You know a little about Perl
and using objects
You know a little bit about
databases and using foreign
keys
3.
DBIx::Class?
• ORM (object relational mapper)
• SQL <-> OO (using objects instead of SQL)
• Simple, powerful, complex, fab and confusing
• There are many ORMs, DBIx::Class just happens to
be the best in Perl (personal opinion)
4.
why this talk?
• Help avoid mistakes I made!
• Help learn DBIx::Class faster
• Make your coding easier
5.
point of note
quot;Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.quot; - Brian W. Kernighan
This talk is about making it easy so we you are less
likely to get confused
8.
authors table
CREATE TABLE authors(
id int(8) primary key auto_increment,
name varchar(255)
) engine = InnoDB DEFAULT CHARSET=utf8;
9.
tips
Name tables as simple plurals (add an S) -
makes relationships easier to understand
(issue: Matt Trout quot;Tables should not be plural as gives you plurals for Result::
package names which represent a single rowquot; - talk may be rewritten in future
to reflect this as this is better once you understand the relationship setup -
either way, consistency is important)
Use a character set (UTF8) from the start
(for international characters)
23.
DBIC: create
my $book = $book_model->create({
title => 'A book title',
author => $author_id,
});
Look ma, no SQL!
Tip: do not pass in primary_key field, even if its empty/undef as the
object returned will have an empty id, even if your field is auto
increment.
24.
DBIC: create
my $book = $book_model->create({
title => 'A book title',
author => $author_id,
});
25.
DBIC: create
my $pratchett = $author_model->create({
name => 'Terry Pratchett',
});
26.
DBIC: create
my $book = $pratchett->create_related(
'books', {
title => 'Another Discworld book',
});
or
my $book = $pratchett->add_to_books({
title => 'Another Discworld book',
});
27.
DBIC: create
my $book = $pratchett->create_related(
'books', {
title => 'Another Discworld book',
});
or
my $book = $pratchett->add_to_books({
title => 'Another Discworld book',
});
28.
DBIC: retrieve
DBIx::Class - Lots of ways to do the same thing...
quot;There is more than one way to do it (TIMTOWTDI,
usually pronounced quot;Tim Toadyquot;) is a Perl mottoquot;
29.
DBIC: retrieve
my $book = $book_model->find($book_id);
my $book = $book_model->search({
title => 'A book title',
})->single();
my @books = $book_model->search({
author => $author_id,
})->all();
30.
DBIC: retrieve
while( my $book = $books_rs->next() ) {
print 'Author of '
. $book->title()
. ' is '
. $book->author()->name()
. quot;nquot;;
}
46.
Result::
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
use strict;
use warnings;
sub isbn {
my $self = shift;
# search amazon or something
my $api = Amazon::API->book({
title => $self->title()
});
return $api->isbn();
}
1;
47.
Result::
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
use strict;
use warnings;
sub isbn {
my $self = shift;
# search amazon or something
my $api = Amazon::API->book({
title => $self->title()
});
return $api->isbn();
}
1;
49.
Result:: (inflating)
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
use strict;
use warnings;
use DateTime::Format::MySQL;
__PACKAGE__->inflate_column(
'date_published',
{ inflate => sub {
DateTime::Format::MySQL->parse_date(shift);
},
deflate => sub {
shift->ymd();
},
}
);
# Automatic see: DBIx::Class::InflateColumn::DateTime
50.
Result:: (inflating)
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
use strict;
use warnings;
use DateTime::Format::MySQL;
__PACKAGE__->inflate_column(
'date_published',
{ inflate => sub {
DateTime::Format::MySQL->parse_date(shift);
},
deflate => sub {
shift->ymd();
},
}
);
# Automatic see: DBIx::Class::InflateColumn::DateTime
52.
Result:: (inflating)
my $date_published = $book->date_published()
print $date_published->month_abbr();
Nov
53.
ResultSets::
package LPW::DBIC::ResultSet::Books;
use base 'DBIx::Class::ResultSet';
sub the_ultimate_books {
my $self = shift;
return $self->search(
{ title => {
'like', '%42%'
}
});
}
sub by_author {
my ( $self, $author ) = @_;
return $self->search( { author => $author->id(), } );
}
1;
54.
ResultSets::
package LPW::DBIC::ResultSet::Books;
use base 'DBIx::Class::ResultSet';
sub the_ultimate_books {
my $self = shift;
return $self->search(
{ title => {
'like', '%42%'
}
});
}
sub by_author {
my ( $self, $author ) = @_;
return $self->search( { author => $author->id(), } );
}
55.
ResultSets::
package LPW::DBIC::ResultSet::Books;
use base 'DBIx::Class::ResultSet';
sub the_ultimate_books {
my $self = shift;
return $self->search(
{ title => {
'like', '%42%'
}
});
}
sub by_author {
my ( $self, $author ) = @_;
return $self->search( {
author => $author->id(),
} );
}
56.
ResultSets::
use LPW::DBIC;
my $book_model = LPW::DBIC->resultset('Books');
my $book_rs = $book_model->the_ultimate_books();
my @books = $book_rs->all();
57.
ResultSets::chaining
use LPW::DBIC;
my $book_model = LPW::DBIC->resultset('Books');
my $author_model = LPW::DBIC->resultset('Authors');
my $author = $author_model->search({
name => 'Douglas Adams',
})->single();
my $book_rs = $book_model->the_ultimate_books()
->by_author($author);
my @books = $book_rs->all();
58.
ResultSets::chaining
my $book_rs = $book_model
->the_ultimate_books()
->by_author($author);
or
my $book_rs = $book_model
->the_ultimate_books();
$book_rs = $book_rs->by_author($author);
# Debug (SQL):
# SELECT me.id, me.title, me.date_published, me.author
# FROM books me
# WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
59.
ResultSets::chaining
my $rs = $book_model
->category('childrens')
->by_author($author)
->published_after('1812')
->first_page_contains('once upon')
->rating_greater_than(4);
my @books = $rs->all();
61.
overloading before
new record
package LPW::DBIC::Result::Authors;
use base 'DBIx::Class';
sub new {
my ( $class, $attrs ) = @_;
# Mess with $attrs
my $new = $class->next::method($attrs);
return $new;
}
1;
69.
has_many
package LPW::DBIC::Result::Books;
__PACKAGE__->has_many(
quot;author_and_booksquot;,
quot;LPW::DBIC::Result::AuthorAndBooksquot;,
{ quot;foreign.bookquot; => quot;self.idquot; },
);
# This is auto generated by Schema::Loader
70.
has_many
package LPW::DBIC::Result::Books;
__PACKAGE__->has_many(
quot;author_and_booksquot;,
# Name of accessor
quot;LPW::DBIC::Result::AuthorAndBooksquot;,
# Related class
{ quot;foreign.bookquot; => quot;self.idquot; },
# Relationship (magic often works if not
# specified, but avoid!)
);
72.
belongs_to
package LPW::DBIC::Result::AuthorAndBooks;
__PACKAGE__->belongs_to(
quot;bookquot;,
quot;LPW::DBIC::Result::Booksquot;,
{ id => quot;bookquot; }
);
# This is auto generated by Schema::Loader
73.
belongs_to
package LPW::DBIC::Result::AuthorAndBooks;
__PACKAGE__->belongs_to(
quot;bookquot;, # Accessor name
quot;LPW::DBIC::Result::Booksquot;, # Related class
{ id => quot;bookquot; } # Relationship
);
74.
same for Authors
has_many
Authors Authors_and_Books
belongs_to
75.
with no coding...
has_many has_many
Authors Authors_and_Books Books
belongs_to belongs_to
77.
many_to_many
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
__PACKAGE__->many_to_many(
quot;authorsquot;
=> quot;author_and_booksquot;,
'author'
);
1;
# This is NOT auto generated by Schema::Loader
78.
many_to_many
package LPW::DBIC::Result::Books;
use base 'DBIx::Class';
__PACKAGE__->many_to_many(
quot;authorsquot;
# Accessor Name
=> quot;author_and_booksquot;,
# has_many accessor_name
'author'
# foreign relationship name
);
1;
79.
many_to_many
package LPW::DBIC::Result::Authors;
use base 'DBIx::Class';
__PACKAGE__->many_to_many(
quot;booksquot;
# Accessor Name
=> quot;author_and_booksquot;,
# has_many accessor_name
'book'
# foreign relationship name
);
1;
# This is NOT auto generated by Schema::Loader
80.
using many_to_many
#!/usr/bin/perl
use LPW::DBIC;
my $author_model = LPW::DBIC->resultset('Authors');
my $author = $author_model->search({
name => 'Douglas Adams',
})->single();
$author->add_to_books({
title => 'A new book',
});
81.
using many_to_many
my $author = $author_model->search({
name => 'Douglas Adams',
})->single();
$author->add_to_books({
title => 'A new book',
});
# SELECT me.id, me.name FROM authors me
# WHERE ( name = ? ): 'Douglas Adams';
# INSERT INTO books (title) VALUES (?): 'A new book';
# INSERT INTO author_and_books (author, book)
# VALUES (?, ?): '5', '2';
82.
using many_to_many
$author->add_to_books($book);
$book->add_to_authors($author_1);
$book->add_to_authors($author_2);
83.
in 16 lines of code
has_many has_many
Authors Authors_and_Books Books
belongs_to belongs_to
many_to_many
85.
error messages
DBIx::Class::Schema::Loader::connection
(): Failed to load external class
definition for
'LPW::DBIC::Result::Authors': Can't
locate object method quot;many_to_manyquot; via
package quot;LPW::DBIC::Result::Authorquot; at
lib/LPW/DBIC/Result/Authors.pm line 9.
Compilation failed in require at /
Library/Perl/5.8.8/DBIx/Class/Schema/
Loader/Base.pm line 292.
86.
error messages
DBIx::Class::Schema::Loader::connection
(): Failed to load external class
definition for
'LPW::DBIC::Result::Authors': Can't
locate object method quot;many_to_manyquot; via
package quot;LPW::DBIC::Result::Authorquot; at
lib/LPW/DBIC/Result/Authors.pm line 9.
Compilation failed in require at /
Library/Perl/5.8.8/DBIx/Class/Schema/
Loader/Base.pm line 292.
87.
errors
• Turn on debugging
• Read error messages (sometimes useful!)
• Check field names
• Check package names
• Check which database you are connected
to (development/test/live?) - repeat above
88.
thanks
http://leo.cuckoo.org/projects/
Time for bonus slides?
89.
Template Toolkit
• [% author.books.count %] not working?
• TT all methods are called in list context
• [% author.books_rs.count %] scalar context
Available for all relationships
90.
Catalyst
package Your::App::Model::LPW;
use base qw(Catalyst::Model::DBIC::Schema);
use strict;
use warnings;
__PACKAGE__->config(
schema_class => 'LPW::DBIC',
);
1;
91.
Catalyst
package Your::App::Model::LPW;
use base qw(Catalyst::Model::DBIC::Schema);
use strict;
use warnings;
__PACKAGE__->config(
schema_class => 'LPW::DBIC',
);
1;
Keep your Scheme in a separate
package to your Catalyst application
92.
Catalyst
sub action_name : Local {
my ($self, $c) = @_;
my $model = $c->model('DBIC::LPW');
my $author_model = $model->resultset('Authors');
}
1;