If your not using an ORM (object relational mapper) and are still writing SQL by hand, here's what you need to know.
An introduction into DBIx::Class and some of the concepts and goodies you should be aware off.
1. DBIx::Class (aka DBIC)
for (advanced) beginners
Leo Lapworth @ YAPC::EU 2010
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
7. authors table
CREATE TABLE authors(
id int(8) primary key auto_increment,
name varchar(255)
) engine = InnoDB DEFAULT CHARSET=utf8;
8. tips
Name tables as simple plurals (add an S) -
makes relationships easier to understand
(issue: Matt Trout "Tables should not be plural as gives you plurals for Result::
package names which represent a single row" - 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)
22. 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.
23. DBIC: create
my $book = $book_model->create({
title => 'A book title',
author => $author_id,
});
25. DBIC: create
my $book = $pratchett->create_related(
'books', {
title => 'Another Discworld book',
});
or
my $book = $pratchett->add_to_books({
title => 'Another Discworld book',
});
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: retrieve
DBIx::Class - Lots of ways to do the same thing...
"There is more than one way to do it (TIMTOWTDI,
usually pronounced "Tim Toady") is a Perl motto"
28. 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();
29. DBIC: retrieve
while( my $book = $books_rs->next() ) {
print 'Author of '
. $book->title()
. ' is '
. $book->author()->name()
. "n";
}
51. Result::
package Bookstore::Schema::Result::Books;
use base 'DBIx::Class';
#...
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2010-08-01 09:19:1
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ta+cEh31lDfqcue3OmUCfQ
sub isbn {
my $self = shift;
# search amazon or something
my $api = Amazon::API->book({
title => $self->title()
});
return $api->isbn();
}
1;
52. Result::
package Bookstore::Schema::Result::Books;
use base 'DBIx::Class';
#...
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2010-08-01 09:19:1
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ta+cEh31lDfqcue3OmUCfQ
sub isbn {
my $self = shift;
# search amazon or something
my $api = Amazon::API->book({
title => $self->title()
});
return $api->isbn();
}
1;
62. ResultSets::chaining
use Bookstore::Schema;
my $book_model = Bookstore::Schema->resultset('Books');
my $author_model = Bookstore::Schema->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();
63. 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 ? ) ) ): '1', '%42%'
64. 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();
66. overloading before
new record
package Bookstore::Schema::Result::Authors;
use base 'DBIx::Class';
sub new {
my ( $class, $attrs ) = @_;
# Mess with $attrs
my $new = $class->next::method($attrs);
return $new;
}
1;
84. many_to_many
package Bookstore::Schema::Result::Authors;
use base 'DBIx::Class';
__PACKAGE__->many_to_many(
"books"
# Accessor Name
=> "author_and_books",
# has_many accessor_name
'book'
# foreign relationship name
);
1;
# This is NOT auto generated by Schema::Loader
85. using many_to_many
#!/usr/bin/perl
use Bookstore::Schema;
my $author_model = Bookstore::Schema->resultset('Authors');
my $author = $author_model->search({
name => 'Douglas Adams',
})->single();
$author->add_to_books({
title => 'A new book',
});
86. 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';
90. error messages
DBIx::Class::Schema::Loader::connection
(): Failed to load external class
definition for
'Bookstore::Schema::Result::Authors':
Can't locate object method
"many_to_many" via package
"Bookstore::Schema::Result::Author" at
lib/Bookstore/Schema/Result/Authors.pm
line 9.
Compilation failed in require at /
Library/Perl/5.8.8/DBIx/Class/Schema/
Loader/Base.pm line 292.
91. error messages
DBIx::Class::Schema::Loader::connection
(): Failed to load external class
definition for
'Bookstore::Schema::Result::Authors':
Can't locate object method
"many_to_many" via package
"Bookstore::Schema::Result::Author" at
lib/Bookstore/Schema/Result/Authors.pm
line 9.
Compilation failed in require at /
Library/Perl/5.8.8/DBIx/Class/Schema/
Loader/Base.pm line 292.
92. 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
94. 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
96. Catalyst
package Your::App::Model::Bookstore;
use base qw(Catalyst::Model::DBIC::Schema);
use strict;
use warnings;
__PACKAGE__->config(
schema_class => 'Bookstore::Schema',
);
1;
Keep your Scheme in a separate
package to your Catalyst application
97. Catalyst
sub action_name : Local {
my ($self, $c) = @_;
my $model = $c->model('Bookstore');
my $author_model = $model->resultset('Authors');
}
1;