Successfully reported this slideshow.
Your SlideShare is downloading. ×

DBIx::Class introduction - 2010

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
DBIx::Class beginners
DBIx::Class beginners
Loading in …3
×

Check these out next

1 of 98 Ad

DBIx::Class introduction - 2010

Download to read offline

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.

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.

Advertisement
Advertisement

More Related Content

Slideshows for you (20)

Viewers also liked (18)

Advertisement

Similar to DBIx::Class introduction - 2010 (20)

Recently uploaded (20)

Advertisement

DBIx::Class introduction - 2010

  1. 1. DBIx::Class (aka DBIC) for (advanced) beginners Leo Lapworth @ YAPC::EU 2010 http://leo.cuckoo.org/projects/
  2. 2. assumptions You know a little about Perl and using objects You know a little bit about databases and using foreign keys
  3. 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. 4. why this talk? • Help avoid mistakes I made! • Help learn DBIx::Class faster • Make your coding easier
  5. 5. table setup
  6. 6. example... Books Authors
  7. 7. authors table CREATE TABLE authors( id int(8) primary key auto_increment, name varchar(255) ) engine = InnoDB DEFAULT CHARSET=utf8;
  8. 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)
  9. 9. authors table CREATE TABLE author s( id int(8) primary key auto_increment, name varchar(255) ) engine = InnoDB DEFAULT CHARSET= utf8;
  10. 10. books table CREATE TABLE books( id int(8) primary key auto_increment, title varchar(255), author int(8), foreign key (author) references authors(id) ) engine = InnoDB DEFAULT CHARSET=utf8;
  11. 11. tips Name link fields as singular Check foreign key is the same field type and size in both tables
  12. 12. books table CREATE TABLE books( id int(8) primary key auto_increment, title varchar(255), author int(8), foreign key ( author) references authors(id) ) engine = InnoDB DEFAULT CHARSET=utf8;
  13. 13. CRUD compared C - Create R - Retrieve U - Update D - Delete
  14. 14. Manual (SQL)
  15. 15. manual: create my $sth = $dbh->prepare(' INSERT INTO books (title, author) values (?,?) '); $sth->execute( 'A book title',$author_id );
  16. 16. manual: create my $sth = $dbh->prepare(' INSERT INTO books (title, author) values (?,?) '); $sth->execute( 'A book title', $author_id );
  17. 17. manual: retrieve my $sth = $dbh->prepare(' SELECT title, authors.name as author_name FROM books, authors WHERE books.author = authors.id ');
  18. 18. manual: retrieve while( my $book = $sth->fetchrow_hashref() ) { print 'Author of ' . $book->{title} . ' is ' . $book->{author_name} . "n"; }
  19. 19. manual: update my $update = $dbh->prepare(' UPDATE books SET title = ? WHERE id = ? '); $update->execute( 'New title', $book_id);
  20. 20. manual: delete my $delete = $dbh->prepare(' DELETE FROM books WHERE id = ? '); $delete->execute( $book_id);
  21. 21. DBIx::Class
  22. 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. 23. DBIC: create my $book = $book_model->create({ title => 'A book title', author => $author_id, });
  24. 24. DBIC: create my $pratchett = $author_model->create({ name => 'Terry Pratchett', });
  25. 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. 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. 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. 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. 29. DBIC: retrieve while( my $book = $books_rs->next() ) { print 'Author of ' . $book->title() . ' is ' . $book->author()->name() . "n"; }
  30. 30. DBIC: retrieve my $books_rs = $book_model->search({ author => $author_id, }); Search takes SQL::Abstract formatted queries > perldoc SQL::Abstract
  31. 31. DBIC: update $book->update({ title => 'New title', });
  32. 32. DBIC: delete $book->delete();
  33. 33. Creating schemas
  34. 34. too much typing! too much maintenance!
  35. 35. Schema::Loader Database introspection -> Code
  36. 36. Use namespaces
  37. 37. Use Namespaces Splits logic cleanly Bookstore::Schema::Result::X = an individual row Bookstore::Schema:: ResultSet::X = searches / results
  38. 38. You can edit this line
  39. 39. Connection details
  40. 40. using your Schema
  41. 41. DEBUGGING DBIC_TRACE=1 ./your_script.pl
  42. 42. SQL - debugging INSERT INTO authors (name) VALUES (?): 'Douglas Adams' INSERT INTO books (author, title) VALUES (?, ?): '1', '42'
  43. 43. overloading Bookstore::Schema::Result::Books Bookstore::Schema::ResultSet::Books Bookstore::Schema::Result::Authors Bookstore::Schema::ResultSet::Authors
  44. 44. 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;
  45. 45. 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;
  46. 46. Result:: print $book->isbn();
  47. 47. Result:: (inflating) package Bookstore::Schema::Result::Books; use base 'DBIx::Class'; #... 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
  48. 48. Result:: (inflating) package Bookstore::Schema::Result::Books; use base 'DBIx::Class'; #... 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
  49. 49. Result:: (deflating) $book->date_published(DateTime->now); $book->update(); 2008-12-31
  50. 50. Result:: (inflating) my $date_published = $book->date_published() print $date_published->month_abbr(); Nov
  51. 51. ResultSets:: package Bookstore::Schema::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(), } ); }
  52. 52. ResultSets:: package Bookstore::Schema::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(), } ); }
  53. 53. ResultSets:: package Bookstore::Schema::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(), } ); }
  54. 54. ResultSets:: use Bookstore::Schema; my $book_model = Bookstore::Schema->resultset('Books'); my $book_rs = $book_model->the_ultimate_books(); my @books = $book_rs->all();
  55. 55. 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();
  56. 56. 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%'
  57. 57. 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();
  58. 58. overloading before new record
  59. 59. 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;
  60. 60. relationships
  61. 61. multiple authors
  62. 62. a few relationships has_many has_many Authors Authors_and_Books Books belongs_to belongs_to many_to_many
  63. 63. a few relationships !
  64. 64. new join table CREATE TABLE author_and_books( id int(8) primary key auto_increment, book ! int(8), author int(8), foreign key (book) references books(id), foreign key (author) references authors(id) ) engine = InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `books` DROP COLUMN `author`;
  65. 65. new join table CREATE TABLE author_and_books( id int(8) primary key auto_increment, book ! int(8), author int(8), foreign key (book) references books(id), foreign key (author) references authors(id) ) engine = InnoDB DEFAULT CHARSET=utf8;
  66. 66. has_many has_many Books Authors_and_Books belongs_to
  67. 67. has_many package Bookstore::Schema::Result::Books; __PACKAGE__->has_many( "author_and_books", "Bookstore::Schema::Result::AuthorAndBooks", { "foreign.book" => "self.id" }, ); # This is auto generated by Schema::Loader
  68. 68. has_many package Bookstore::Schema::Result::Books; __PACKAGE__->has_many( "author_and_books", # Name of accessor "Bookstore::Schema::Result::AuthorAndBooks", # Related class { "foreign.book" => "self.id" }, # Relationship (magic often works if not # specified, but avoid!) );
  69. 69. belongs_to has_many Books Authors_and_Books belongs_to
  70. 70. belongs_to package Bookstore::Schema::Result::AuthorAndBooks; __PACKAGE__->belongs_to( "book", "Bookstore::Schema::Result::Books", { id => "book" } ); # This is auto generated by Schema::Loader
  71. 71. belongs_to package Bookstore::Schema::Result::AuthorAndBooks; __PACKAGE__->belongs_to( "book", # Accessor name "Bookstore::Schema::Result::Books", # Related class { id => "book" } # Relationship );
  72. 72. same for Authors has_many Authors Authors_and_Books belongs_to
  73. 73. with no coding... has_many has_many Authors Authors_and_Books Books belongs_to belongs_to
  74. 74. many_to_many has_many has_many Authors Authors_and_Books Books belongs_to belongs_to many_to_many
  75. 75. many_to_many package Bookstore::Schema::Result::Books; use base 'DBIx::Class'; __PACKAGE__->many_to_many( "authors" => "author_and_books", 'author' ); 1; # This is NOT auto generated by Schema::Loader
  76. 76. many_to_many package Bookstore::Schema::Result::Books; use base 'DBIx::Class'; __PACKAGE__->many_to_many( "authors" # Accessor Name => "author_and_books", # has_many accessor_name 'author' # foreign relationship name ); 1;
  77. 77. 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
  78. 78. 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', });
  79. 79. 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';
  80. 80. using many_to_many $author->add_to_books($book); $book->add_to_authors($author_1); $book->add_to_authors($author_2);
  81. 81. in 16 lines of code has_many has_many Authors Authors_and_Books Books belongs_to belongs_to many_to_many
  82. 82. errors Read them closely!
  83. 83. 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.
  84. 84. 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.
  85. 85. 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
  86. 86. thanks http://leo.cuckoo.org/projects/ Time for bonus slides?
  87. 87. 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
  88. 88. Catalyst package Your::App::Model::Bookstore; use base qw(Catalyst::Model::DBIC::Schema); use strict; use warnings; __PACKAGE__->config( schema_class => 'Bookstore::Schema', ); 1;
  89. 89. 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
  90. 90. Catalyst sub action_name : Local { my ($self, $c) = @_; my $model = $c->model('Bookstore'); my $author_model = $model->resultset('Authors'); } 1;
  91. 91. thanks! http://leo.cuckoo.org/projects/

×