f75172735602a54103e542f0d61f3697af0b3b47
[dbsrgits/dbix-class-introduction-presentation.git] / slideshow.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
4 <html xmlns="http://www.w3.org/1999/xhtml">
5
6 <head>
7 <title>DBIx::Class (aka DBIC)</title>
8 <!-- metadata -->
9 <meta name="contributor" content="youcan[64]netzgesta[46]de" />
10 <meta name="publisher" content="s5.netzgesta.de" />
11 <meta name="description" content="S5 1.3 is a very flexible and lightweight slide show system available for anyone to use (including transitions and scalable fonts and images)" />
12 <meta name="keywords" content="S5, version 1.3, slide show, presentation-mode, projection-mode, powerpoint-like, scala-like, keynote-like, incremental display, scalable fonts, scalable images, transitions, notes, osf, xoxo, css, javascript, xhtml, public domain" />
13
14 <meta name="generator" content="S5" />
15 <meta name="version" content="1" />
16 <meta name="subject" content="DBIx::Class" />
17 <meta name="author" content="See first slide" />
18 <meta name="company" content="N/A" />
19 <meta name="robots" content="index, follow" />
20 <meta name="revisit-after" content="7 days" />
21 <!-- meta additionally -->
22 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
23 <meta http-equiv="Content-Script-Type" content="text/javascript" />
24 <meta http-equiv="Content-Style-Type" content="text/css" /><!-- configuration parameters -->
25 <meta name="defaultView" content="slideshow" />
26 <meta name="controlVis" content="hidden" />
27 <!-- configuration transition extension -->
28 <meta name="tranSitions" content="true" />
29 <meta name="fadeDuration" content="500" />
30 <meta name="incrDuration" content="250" />
31 <!-- configuration autoplay extension -->
32 <meta name="autoMatic" content="false" />
33 <meta name="playLoop" content="true" />
34 <meta name="playDelay" content="10" />
35 <!-- configuration audio extension -->
36 <meta name="audioSupport" content="false" />
37 <meta name="audioVolume" content="0" />
38 <meta name="audioError" content="false" />
39 <!-- configuration audio debug -->
40 <meta name="audioDebug" content="false" />
41 <!-- style sheet links -->
42 <link rel="stylesheet" href="ui/scala_utf/slides.css" type="text/css" media="projection" id="slideProj" />
43 <link rel="stylesheet" href="ui/scala_utf/outline.css" type="text/css" media="screen" id="outlineStyle" />
44 <link rel="stylesheet" href="ui/scala_utf/print.css" type="text/css" media="print" id="slidePrint" />
45 <link rel="stylesheet" href="ui/scala_utf/opera.css" type="text/css" media="projection" id="operaFix" />
46 <!-- embedded styles -->
47 <style type="text/css" media="all">
48 .imgcon {width: 100%; margin: 0 auto; padding: 0; text-align: center;}
49 #anim {width: 33%; height: 320px; position: relative;}
50 #anim img {position: absolute; top: 0px; left: 0px;}
51 .red {color: red;}
52 .grey {color: gray;}
53 </style>
54 <!-- S5 JS -->
55 <script src="ui/scala_utf/slides.js" type="text/javascript"></script>
56 </head>
57 <body>
58
59 <div class="layout">
60    <div id="controls"><!-- DO NOT EDIT --></div>
61    <div id="currentSlide"><!-- DO NOT EDIT --></div>
62    <div id="header"></div>
63    <div id="footer">
64       <h1>DBIx::Class Introduction</h1>
65       <h2>YAPC::NA 2010</h2>
66    </div>
67 </div>
68
69 <div class="presentation">
70
71    <div class="slide">
72       <h1>DBIX::Class (aka DBIC)</h1>
73       <h3>for (advanced) beginners</h3>
74    </div>
75
76    <div class="slide">
77       <h1>Authors</h1>
78       <h4>Originally Leo Lapworth @ LPW 2009</h4>
79       <h4>Matthew S. Trout</h4>
80       <h4>Justin D. Hunter</h4>
81       <h4>Arthur Axel "fREW" Schmidt</h4>
82    </div>
83
84    <div class="slide">
85       <h1>assumptions</h1>
86       <p>You know a little about Perl and using objects</p>
87       <p>You know a little bit about databases and using foreign keys</p>
88       <div class="notes">
89          <ul>
90             <li>How many people have designed a database with Foreign Keys?</li>
91             <li>How many people have used any ORM?<ul>
92                <li>In Perl?<ul>
93                   <li>DBIC?</li>
94                   <li> Class::DBI? </li>
95                   <li> Rose::DB?  </li>
96                   <li> Fey?  </li>
97                   <li> Others?  </li>
98                </ul></li>
99                <li>AR? </li>
100                <li> DataMapper?  </li>
101                <li>(N)Hibernate?</li>
102             </ul></li>
103          </ul>
104       </div>
105    </div>
106
107    <div class="slide">
108       <h1>DBIx::Class?</h1>
109       <ul>
110          <li>ORM (object relational mapper)</li>
111          <li>SQL &lt;-&gt; OO (using objects instead of SQL)</li>
112          <li>Simple, powerful, complex, fab and confusing</li>
113          <li>There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)</li>
114       </ul>
115    </div>
116
117    <div class="slide">
118       <h1>point of note</h1>
119       <p><em>"Debugging is twice as hard as writing the code in the first
120       place. Therefore, if you write the code as cleverly as possible,
121       you are, by definition, not smart enough to debug it." - Brian
122       W. Kernighan</em></p>
123
124       <p>This talk is about making it easy so we are less likely to get
125       confused</p>
126    </div>
127
128    <div class="slide">
129       <h1>Examples Table Setup</h1>
130       <ul>
131          <li>Authors</li>
132          <li>Books</li>
133       </ul>
134       <em>MySQL not recommended</em>
135    </div>
136
137    <div class="slide">
138       <h1>authors table</h1>
139 <pre>CREATE TABLE authors(
140    id   int(8) primary key auto_increment,
141    name varchar(255)
142 ) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
143    </div>
144
145    <div class="slide">
146       <h1>tips</h1>
147       <p>Name tables as simple plurals (<strong>add an S</strong>) - makes relationships easier to understand</p>
148       <p>Use a character set (<strong>UTF8</strong>) from the start (for international characters)</p>
149    </div>
150
151    <div class="slide">
152       <h1>authors table</h1>
153 <pre>CREATE TABLE author<strong>s</strong>(
154    id   int(8) primary key auto_increment,
155    name varchar(255)
156 ) engine = <strong>InnoDB</strong> DEFAULT CHARSET=<strong>utf8</strong>;</pre>
157    </div>
158
159    <div class="slide">
160       <h1>books table</h1>
161 <pre>CREATE TABLE books(
162    id        int(8) primary key auto_increment,
163    title     varchar(255),
164    author_id int(8),foreign key (author)
165       references authors(id)
166 ) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
167    </div>
168
169
170    <div class="slide">
171       <h1>tips</h1>
172       <p>Name link fields as singular</p>
173       <p>Ensure foreign key is the same type and size in both tables</p>
174    </div>
175
176    <div class="slide">
177       <h1>books table</h1>
178 <pre>CREATE TABLE books(
179    id        int(8) primary key auto_increment,
180    title     varchar(255),
181    author_id <strong>int(8)</strong>,<strong>foreign key (<em>author</em>)</strong>
182       <strong>references <em>authors(id)</em></strong>
183 ) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
184    </div>
185
186    <div class="slide">
187       <h1>CRUD compared</h1>
188       <ul>
189          <li><strong>C</strong> - Create</li>
190          <li><strong>R</strong> - Read</li>
191          <li><strong>U</strong> - Update</li>
192          <li><strong>D</strong> - Delete</li>
193       </ul>
194    </div>
195
196    <div class="slide">
197       <h1>Manual (SQL)</h1>
198    </div>
199
200    <div class="slide">
201       <h1>SQL: Create</h1>
202 <pre>my $sth = $dbh-&gt;prepare('
203    INSERT INTO books
204    (title, author)
205    values (?,?)
206 ');
207
208 $sth-&gt;execute(
209   'A book title', $author_id
210 );</pre>
211    </div>
212
213    <div class="slide">
214       <h1>SQL: Read</h1>
215 <pre>my $sth = $dbh-&gt;prepare('
216    SELECT title,
217    authors.name as author_name
218    FROM books, authors
219    WHERE books.author = authors.id
220 ');</pre>
221    </div>
222
223    <div class="slide">
224       <h1>SQL: Read</h1>
225 <pre>while( my $book = $sth-&gt;fetchrow_hashref() ) {
226   print 'Author of '
227      . $book-&gt;{title}
228      . ' is '
229      . $book-&gt;{author_name}
230      . "\n";
231 }</pre>
232    </div>
233
234    <div class="slide">
235       <h1>SQL: Update</h1>
236 <pre>my $update = $dbh-&gt;prepare('
237    UPDATE books
238    SET title = ?
239    WHERE id = ?
240 ');
241
242 $update-&gt;execute(
243   'New title',<strong>$book_id</strong>
244 );</pre>
245    </div>
246
247    <div class="slide">
248       <h1>SQL: Delete</h1>
249 <pre>my $delete = $dbh-&gt;prepare('
250    DELETE FROM books
251    WHERE id = ?
252 ');
253
254 $delete-&gt;execute(<strong>$book_id</strong>);</pre>
255    </div>
256
257    <div class="slide">
258       <h1>DBIx::Class</h1>
259    </div>
260
261    <div class="slide">
262       <h1>DBIC: Create</h1>
263 <pre>my $book = $book_model-&gt;create({
264    title  =&gt; 'A book title',
265    author =&gt; $author_id,
266 });</pre>
267       <p>Look ma, no SQL!</p>
268    </div>
269
270    <div class="slide">
271       <h1>DBIC: Create</h1>
272 <pre>my $pratchett = $author_model-&gt;create({
273    name =&gt; 'Terry Pratchett',
274 });</pre>
275    </div>
276
277    <div class="slide">
278       <h1>DBIC: Create</h1>
279 <pre>my $book = $pratchett-&gt;create_related(
280   <strong>books</strong> =&gt; {
281    title =&gt; 'Another Discworld book',
282 });</pre>
283 <strong>or</strong>
284 <pre>my $book = $pratchett-&gt;add_to_<strong>books</strong>({
285    title =&gt; 'Another Discworld book',
286 });</pre>
287    </div>
288
289    <div class="slide">
290       <h1>DBIC: Read</h1>
291       <p>DBIx::Class - Lots of ways to do the same thing...</p>
292       <p><em>"There is more than one way to do it (TIMTOWTDI, usually pronounced "Tim Toady") is a Perl motto"</em></p>
293    </div>
294
295    <div class="slide">
296       <h1>DBIC: Read</h1>
297 <pre>my $book = $book_model-&gt;find($book_id);
298
299 my $book = $book_model-&gt;search({
300    title =&gt; 'A book title',
301 }, { rows =&gt; 1 })-&gt;single;
302
303 my @books = $book_model-&gt;search({
304    author =&gt; $author_id,
305 })-&gt;all;</pre>
306    </div>
307
308    <div class="slide">
309       <h1>DBIC: Read</h1>
310 <pre>while( my $book = $books_rs-&gt;next ) {
311  print 'Author of '
312     . $book-&gt;title
313     . ' is '
314     . $book-&gt;author-&gt;name
315     . "\n";
316 }</pre>
317    </div>
318
319    <div class="slide">
320       <h1>DBIC: Read</h1>
321 <pre>my $books_rs = $book_rs-&gt;search({
322    author =&gt; $author_id,
323 });</pre>
324       <p>Search takes SQL::Abstract formatted queries</p>
325       <pre>&gt; perldoc SQL::Abstract</p>
326    </div>
327
328    <div class="slide">
329       <h1>DBIC: Update</h1>
330 <pre>$book-&gt;update({
331   title =&gt; 'New title',
332 });</pre>
333    </div>
334
335    <div class="slide">
336       <h1>DBIC: Delete</h1>
337 <pre>$book-&gt;delete;</pre>
338    </div>
339
340    <div class="slide">
341       <h1>Creating models</h1>
342    </div>
343
344    <div class="slide">
345       <pre>Example of a DBIC Result</pre>
346    </div>
347
348    <div class="slide">
349       <pre>Example of a DBIC Result</pre>
350    </div>
351
352    <div class="slide">
353       <p>too much typing!  too much maintenance!</p>
354    </div>
355
356    <div class="slide">
357       <h1>Schema::Loader</h1>
358       <pre>code for S::L here</pre>
359    </div>
360
361    <div class="slide">
362       <h1>splitting logic cleanly</h1>
363       <p>Foo::Schema::Result::Foo = an individual row</p>
364       <p>Foo::Schema::ResultSet::Foo = searches / results</p>
365    </div>
366
367    <div class="slide">
368       <h1>using your Schema</h1>
369       <pre>example usage code goes here</pre>
370    </div>
371
372    <div class="slide">
373       <h1>DEBUGGING</h1>
374       <pre>DBIC_TRACE=1 ./your_script.pl</pre>
375    </div>
376
377    <div class="slide">
378       <h1>Schema::Loader</h1>
379 <pre>Foo::Schema::Result::Authors-&gt;table("authors");
380 Foo::Schema::Result::Authors-&gt;add_columns(
381    id =&gt; {
382       data_type     =&gt; "INT",
383       default_value =&gt; undef,
384       is_nullable   =&gt; 0,
385       size          =&gt; 8
386    },
387    title =&gt; {
388       data_type     =&gt; "VARCHAR",
389       default_value =&gt; undef,
390       is_nullable   =&gt; 1,
391       size          =&gt; 255,
392    },
393 );
394 Foo::Schema::Result::Authors-&gt;set_primary_key("id");</pre>
395    </div>
396
397    <div class="slide">
398       <h1>Schema::Loader</h1>
399 <pre>Foo::Schema::Result::Books->table("books");
400 Foo::Schema::Result::Books->add_columns(
401    id =&gt; {
402       data_type     =&gt; "INT",
403       default_value =&gt; undef,
404       is_nullable   =&gt; 0,
405       size          =&gt; 8
406    },
407    name =&gt; {
408       data_type     =&gt; "VARCHAR",
409       default_value =&gt; undef,
410       is_nullable   =&gt; 1,
411       size          =&gt; 255,
412    },
413    author =&gt; {
414       data_type     =&gt; "INT",
415       default_value =&gt; undef,
416       is_nullable   =&gt; 1,
417       size          =&gt; 8
418    },
419 );
420 Foo::Schema::Result::Books-&gt;set_primary_key("id");</pre>
421    </div>
422
423    <div class="slide">
424       <h1>Schema::Loader</h1>
425 <pre>Foo::Schema::Result::Authors-&gt;has_many(books =&gt; "Foo::Schema::Books",
426    { "foreign.author" =&gt; "self.id" });
427
428 Foo::Schema::Result::Books-&gt;belongs_to(author =&gt; "Foo::Schema::Authors",
429    { id =&gt; "author" });</pre>
430    </div>
431
432    <div class="slide">
433       <h1>SQL - debugging</h1>
434 <pre>INSERT INTO authors (name)
435    VALUES (?): 'Douglas Adams'
436
437 INSERT INTO books (author, title)
438    VALUES (?, ?): '5', '42'</pre>
439    </div>
440
441    <div class="slide">
442       <h1>overloading</h1>
443 <pre>Foo::Schema::Result::Books
444 Foo::Schema::ResultSet::Books
445 Foo::Schema::Result::Authors
446 Foo::Schema::ResultSet::Books</pre>
447    </div>
448
449    <div class="slide">
450       <h1>Result::</h1>
451 <pre>package Foo::Schema::Result::Books;
452 use base 'DBIx::Class';
453 use strict;
454 use warnings;
455
456 sub isbn {
457    my $self = shift;
458
459    # search amazon or something
460    my $api = Amazon::API-&gt;book({
461       title =&gt; $self-&gt;title
462    });
463
464    return $api-&gt;isbn;
465 }
466
467 1;</pre>
468    </div>
469
470    <div class="slide">
471       <h1>Result::</h1>
472 <pre>print $book-&gt;isbn;</pre>
473    </div>
474
475    <div class="slide">
476       <h1>Result:: (inflating)</h1>
477 <pre>package Foo::Schema::Result::Books;
478 use base 'DBIx::Class';
479 use strict;
480 use warnings;
481
482 use DateTime::Format::MySQL;
483
484 __PACKAGE__-&gt;<strong>inflate_column</strong>(
485    <strong>date_published</strong> =&gt; {
486       inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
487       deflate =&gt; sub { shift-&gt;ymd},
488    }
489 );
490 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
491    </div>
492
493    <div class="slide">
494       <h1>Result:: (inflating)</h1>
495 <pre>package Foo::Schema::Result::Books;
496 use base 'DBIx::Class';
497 use strict;
498 use warnings;
499
500 use DateTime::Format::MySQL;
501
502 __PACKAGE__-&gt;inflate_column(
503    date_published =&gt; {
504       <strong>inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
505       deflate =&gt; sub { shift-&gt;ymd},</strong>
506    }
507 );
508 # Automatic see: DBIx::Class::InflateColumn::DateTime
509 # Automatic see: DBIx::Class::InflateColumn::DateTime
510 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
511    </div>
512
513    <div class="slide">
514       <h1>Result:: (deflating)</h1>
515 <pre>$book-&gt;date_published(DateTime-&gt;now);
516 $book-&gt;update;</pre>
517    </div>
518
519    <div class="slide">
520       <h1>Result:: (inflating)</h1>
521 <pre>my $date_published = $book-&gt;date_published;
522 print $date_published-&gt;month_abbr;</pre>
523
524 <strong><em>Nov</em></strong>
525    </div>
526
527    <div class="slide">
528       <h1>ResultSets::</h1>
529 <pre>package Foo::Schema::ResultSet::Books;
530 use base 'DBIx::Class::ResultSet';
531 sub the_ultimate_books {
532    my $self = shift;
533    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
534 }
535 sub by_author {
536    my ( $self, $author ) = @_;
537    return $self-&gt;search({ author =&gt; $author-&gt;id })
538 }
539
540 1;</pre>
541    </div>
542
543    <div class="slide">
544       <h1>ResultSets::</h1>
545 <pre>package Foo::Schema::<strong>ResultSet::Books</strong>;
546 use base '<strong>DBIx::Class::ResultSet</strong>';
547 sub the_ultimate_books {
548    my $self = shift;
549    <strong>return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } })</strong>
550 }
551 sub by_author {
552    my ( $self, $author ) = @_;
553    return $self-&gt;search({ author =&gt; $author-&gt;id })
554 }
555
556 1;</pre>
557    </div>
558
559    <div class="slide">
560       <h1>ResultSets::</h1>
561 <pre>package Foo::Schema::ResultSet::Books;
562 use base 'DBIx::Class::ResultSet';
563 sub the_ultimate_books {
564    my $self = shift;
565    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
566 }
567 sub by_author {
568    my ( $self, $author ) = @_;
569    <strong>return $self-&gt;search({ author =&gt; $author-&gt;id })</strong>
570 }
571
572 1;</pre>
573    </div>
574
575    <div class="slide">
576       <h1>ResultSets::</h1>
577 <pre>use Foo::Schema;
578 my $book_model = Foo::Schema-&gt;resultset('Books');
579 my $book_rs    = $book_model-&gt;the_ultimate_books;
580 my @books      = $book_rs-&gt;all;</pre>
581    </div>
582
583    <div class="slide">
584       <h1>ResultSets::chaining</h1>
585 <pre>use Foo::Schema;
586 my $book_model   = Foo::Schema-&gt;resultset('Books');
587 my $author_model = Foo::Schema-&gt;resultset('Authors');
588 my $author       = $author_model-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
589 my $book_rs      = $book_model-&gt;the_ultimate_books-&gt;by_author($author);
590 my @books        = $book_rs-&gt;all;</pre>
591    </div>
592
593    <div class="slide">
594       <h1>ResultSets::chaining</h1>
595 <pre>my $book_rs = $book_model
596   -&gt;the_ultimate_books
597   -&gt;by_author($author);</pre>
598 or
599
600 <pre>my $book_rs = $book_model
601   -&gt;the_ultimate_books();
602 $book_rs = $book_rs-&gt;by_author($author);</pre>
603 <pre># Debug (SQL):
604
605 # SELECT me.id, me.title, me.date_published, me.author
606 #   FROM books me
607 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
608 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre>
609    </div>
610
611    <div class="slide">
612       <h1>ResultSets::chaining</h1>
613 <pre>my $rs = $book_model
614   -&gt;category('childrens')
615   -&gt;by_author($author)
616   -&gt;published_after('1812')
617   -&gt;first_page_contains('once upon')
618   -&gt;rating_greater_than(4);
619
620 my @books = $rs-&gt;all;</pre>
621    </div>
622
623    <div class="slide">
624       <h1>overloading before new record</h1>
625    </div>
626
627    <div class="slide">
628       <h1>overloading before new record</h1>
629       <pre>package Foo::Schema::Result::Authors;
630 use base 'DBIx::Class';
631
632 sub new {
633    my ( $class, $attrs ) = @_;
634    # Mess with $attrs
635    my $new = $class-&gt;next::method($attrs);
636    return $new
637 }
638
639 1;</pre>
640
641    <div class="slide">
642       <h1>relationships</h1>
643    </div>
644
645    <div class="slide">
646       <h1>multiple authors</h1>
647    </div>
648
649    <div class="slide">
650       <h1>a few relationships</h1>
651       (authors -- author_link_to_book -- books)
652    </div>
653
654    <div class="slide">
655       <h1>a few relationships</h1>
656       !
657    </div>
658
659    <div class="slide">
660       <h1>new join table</h1>
661 <pre>CREATE TABLE author_and_books(
662   id      int(8)    primary key auto_increment,
663   book    int(8),
664   author  int(8),
665   foreign key (book)     references books(id),
666   foreign key (author)   references authors(id)
667 ) engine = InnoDB DEFAULT CHARSET=utf8;
668
669 ALTER TABLE `books` DROP `author`</pre>
670    </div>
671
672    <div class="slide">
673       <h1>new join table</h1>
674 <pre>CREATE TABLE author_and_books(
675   id      int(8)    primary key auto_increment,
676   book    int(8),
677   author  int(8),
678   <strong>foreign key (book)     references books(id),
679   foreign key (author)   references authors(id)</strong>
680 ) engine = InnoDB DEFAULT CHARSET=utf8;
681
682 ALTER TABLE `books` DROP `author`</pre>
683    </div>
684
685    <div class="slide">
686       <h1>has_many</h1>
687    </div>
688
689    <div class="slide">
690       <h1>has_many</h1>
691 <pre>package Foo::Schema::<strong>Result::Books</strong>;
692
693 __PACKAGE__-&gt;has_many( author_and_books =&gt; "Foo::Schema::Result::AuthorAndBooks",
694     { "foreign.book" =&gt; "self.id" },
695 );
696
697 <strong># This is auto generated by Schema::Loader</strong></pre>
698    </div>
699
700    <div class="slide">
701       <h1>has_many</h1>
702 <pre>package Foo::Schema::<strong>Result::Books</strong>;
703
704 __PACKAGE__-&gt;has_many(
705 author_and_books =&gt; <strong># name of accessor</strong>
706 "Foo::Schema::Result::AuthorAndBooks", <strong># related class</strong>
707     { "foreign.book" =&gt; "self.id" } <strong># Relationship (magic often works if not
708                                         # specified, but avoid!)</strong>
709 );
710 </pre>
711    </div>
712
713    <div class="slide">
714       <h1>belongs_to</h1>
715    </div>
716
717    <div class="slide">
718       <h1>belongs_to</h1>
719 <pre>package Foo::Schema::<strong>Result::AuthorAndBooks</strong>;
720
721 __PACKAGE__-&gt;belongs_to(
722    book =&gt; <strong># Accessor name</strong>
723    "Foo::Schema::Result::Books", <strong># Related class</strong>
724    { id =&gt; "book" } <strong># relationship</strong>
725 );
726 </pre>
727    </div>
728
729    <div class="slide">
730       <h1>same for Authors</h1>
731    </div>
732
733    <div class="slide">
734       <h1>with no coding...</h1>
735    </div>
736
737    <div class="slide">
738       <h1>many_to_many</h1>
739    </div>
740
741    <div class="slide">
742       <h1>many_to_many</h1>
743       <pre>package Foo::Schema::<strong>Result::Books</strong>;
744 use base 'DBIx::Class';
745
746 __PACKAGE__-&gt;many_to_many(
747    authors =&gt; "author_and_books", 'author'
748 );
749
750 1;
751
752 <strong> # This is <em>NOT</em> auto generated by Schema::Loader </strong></pre>
753    </div>
754
755    <div class="slide">
756       <h1>many_to_many</h1>
757       <pre>package Foo::Schema::<strong>Result::Books</strong>;
758 use base 'DBIx::Class';
759
760 __PACKAGE__-&gt;many_to_many(
761    authors <strong># Accessor name</strong>
762    =&gt; "author_and_books", <strong># has_many</strong>
763    'author' <strong># foreign relationship name</strong>
764 );
765
766 1;</pre>
767    </div>
768
769    <div class="slide">
770       <h1>many_to_many</h1>
771       <pre>package Foo::Schema::Result::Authors;
772 use base 'DBIx::Class';
773
774 __PACKAGE__-&gt;many_to_many(
775    "books" <strong># Accessor Name</strong>
776    =&gt; "author_and_books", <strong># has_many accessor_name</strong>
777    'book' <strong># foreign relationship name</strong>
778 );
779
780 1;
781
782 <strong># This is <em>NOT</em> auto generated by Schema::Loader</strong></pre>
783    </div>
784
785    <div class="slide">
786       <h1>using many_to_many</h1>
787       <pre>#!/usr/bin/perl
788
789 use Foo::Schema;
790
791 my $author_model = Foo::Schema-&gt;resultset('Authors');
792 my $author       = $author_model-&gt;search({
793    name =&gt; 'Douglas Adams',
794 })-&gt;single;
795 $author-&gt;add_to_books({
796    title =&gt; 'A new book',
797 });</pre>
798    </div>
799
800    <div class="slide">
801       <h1>using many_to_many</h1>
802       <pre>my $author = $author_model-&gt;search({
803    name =&gt; 'Douglas Adams',
804 })-&gt;single;
805 <strong>$author-&gt;add_to_books({
806    title =&gt; 'A new book',
807 });</strong>
808
809 # SELECT me.id, me.name FROM authors me
810 #     WHERE ( name = ? ): 'Douglas Adams';
811 # INSERT INTO books (title) VALUES (?): 'A new book';
812 # INSERT INTO author_and_books (author, book)
813 #     VALUES (?, ?): '5', '2';</pre>
814    </div>
815
816    <div class="slide">
817       <h1>using many_to_many</h1>
818       <pre>$author-&gt;add_to_books($book);
819
820 $book-&gt;add_to_authors($author_1);
821 $book-&gt;add_to_authors($author_2);</pre>
822    </div>
823
824    <div class="slide">
825       <h1>in 16 lines of code</h1>
826    </div>
827
828    <div class="slide">
829       <h1>errors</h1>
830       <p>Read them closely!</p>
831    </div>
832
833    <div class="slide">
834       <h1>error messages</h1>
835       <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'Foo::Schema::Result::Authors': Can't locate object method "many_to_many" via package "Foo::Schema::Result::Author" at lib/Foo/Schema/Result/Authors.pm line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre>
836    </div>
837
838    <div class="slide">
839       <h1>error messages</h1>
840    <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'Foo::Schema::Result::Authors': Can't locate object method "many_to_many" via package "Foo::Schema::<strong>Result::Author</strong>" at lib/Foo/Schema/<strong>Result/Authors.pm</strong> line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre>
841    </div>
842
843    <div class="slide">
844       <h1>errors</h1>
845       <ul>
846          <li>Turn on debugging</li>
847          <li>Read error messages (sometimes useful!)</li>
848          <li>Check field names</li>
849          <li>Check package names</li>
850          <li>Check which database you are connected to (dev/test/live?) - repeat above</li>
851       </ul>
852    </div>
853
854    <div class="slide">
855       <h1>bonus slides!</h1>
856    </div>
857
858    <div class="slide">
859       <h1>Template Toolkit</h1>
860       <ul>
861          <li><pre>[% author.books.count %]</pre> not working?</li>
862          <li>TT all methods are called in list context</li>
863          <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li>
864          <li><em>Available for all relationships</em></li>
865       </ul>
866    </div>
867
868    <div class="slide">
869       <h1>Catalyst</h1>
870       <pre>package Your::App::Model::<strong>Foo</strong>;
871 use base qw(<strong>Catalyst::Model::Schema::Schema</strong>);
872
873 use strict;
874 use warnings;
875
876 __PACKAGE__-&gt;config(
877   schema_class =&gt; '<strong>Foo::Schema</strong>',
878 );
879
880 1;</pre>
881    <p>Keep your Schema in a <em>separate</em> package to your Catalyst application</p>
882    </div>
883
884    <div class="slide">
885       <h1>Catalyst</h1>
886 <pre>sub action_name : Local {
887   my ($self, $c) = @_;
888
889   my $model = $c-&gt;model('Schema::Foo');
890   my $author_model = $model-&gt;resultset('Authors');
891
892 }
893
894 1;</pre>
895    </div>
896
897 </div>
898 </body>
899 </html>