ad49e67d7e649f5ba34b4d0ec9cee58a3ec01fdc
[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>package MyApp::Schema::Result::Author;
346 use strict; use warnings;
347 __PACKAGE__-&gt;table('authors');
348 __PACKAGE__-&gt;add_columns(
349   id =&gt; {
350     data_type =&gt; 'int',
351     size      =&gt; 8,
352   },
353   title =&gt; {
354     data_type   =&gt; 'varchar',
355     is_nullable =&gt; 1,
356     size        =&gt; 255,
357   },
358 );
359 __PACKAGE__-&gt;set_primary_key('id');
360 __PACKAGE__-&gt;has_many( books =&gt;
361    'MyApp::Schema::Result::Book', 'author_id'
362 );
363 1;
364 </pre>
365    </div>
366
367    <div class="slide">
368 <pre>package MyApp::Schema::Result::Book;
369 use strict; use warnings;
370 __PACKAGE__-&gt;table('books');
371 __PACKAGE__-&gt;add_columns(
372   id =&gt; {
373     data_type =&gt; 'int',
374     size      =&gt; 8,
375   },
376   name =&gt; {
377     data_type   =&gt; 'varchar',
378     is_nullable =&gt; 1,
379     size        =&gt; 255,
380   },
381   author_id =&gt; {
382     data_type   =&gt; 'int',
383     size        =&gt; 8,
384     is_nullable =&gt; 1, # &lt;-- probably should be 0
385   },
386 );
387 __PACKAGE__-&gt;set_primary_key('id');
388 __PACKAGE__-&gt;belongs_to( author =&gt;
389    'MyApp::Schema::Result::Author', 'author_id'
390 );
391 1;
392 </pre>
393    </div>
394
395    <div class="slide">
396       <h1>Schema::Loader</h1>
397       <p>DB -&gt; Perl vs Perl -&gt; DB</p>
398 <pre>package MyApp::Schema;
399 use strict; use warnings;
400 use base 'DBIx::Class::Schema::Loader';
401 __PACKAGE__-&gt;loader_options({
402    naming =&gt; 'v7',
403    debug  =&gt; $ENV{DBIC_TRACE},
404 });
405 1;
406
407 # elsewhere...
408
409 my $schema = MyApp::Schema-&gt;connect($dsn, $user, $pass);
410 </pre>
411    </div>
412
413    <div class="slide">
414       <h1>splitting logic cleanly</h1>
415       <p>Foo::Schema::Result::Foo = an individual row</p>
416       <p>Foo::Schema::ResultSet::Foo = searches / results</p>
417    </div>
418
419    <div class="slide">
420       <h1>using your Schema</h1>
421       <pre>example usage code goes here</pre>
422    </div>
423
424    <div class="slide">
425       <h1>DEBUGGING</h1>
426       <pre>DBIC_TRACE=1 ./your_script.pl</pre>
427    </div>
428
429    <div class="slide">
430       <h1>Schema::Loader</h1>
431 <pre>Foo::Schema::Result::Authors-&gt;table("authors");
432 Foo::Schema::Result::Authors-&gt;add_columns(
433    id =&gt; {
434       data_type     =&gt; "INT",
435       default_value =&gt; undef,
436       is_nullable   =&gt; 0,
437       size          =&gt; 8
438    },
439    title =&gt; {
440       data_type     =&gt; "VARCHAR",
441       default_value =&gt; undef,
442       is_nullable   =&gt; 1,
443       size          =&gt; 255,
444    },
445 );
446 Foo::Schema::Result::Authors-&gt;set_primary_key("id");</pre>
447    </div>
448
449    <div class="slide">
450       <h1>Schema::Loader</h1>
451 <pre>Foo::Schema::Result::Books->table("books");
452 Foo::Schema::Result::Books->add_columns(
453    id =&gt; {
454       data_type     =&gt; "INT",
455       default_value =&gt; undef,
456       is_nullable   =&gt; 0,
457       size          =&gt; 8
458    },
459    name =&gt; {
460       data_type     =&gt; "VARCHAR",
461       default_value =&gt; undef,
462       is_nullable   =&gt; 1,
463       size          =&gt; 255,
464    },
465    author =&gt; {
466       data_type     =&gt; "INT",
467       default_value =&gt; undef,
468       is_nullable   =&gt; 1,
469       size          =&gt; 8
470    },
471 );
472 Foo::Schema::Result::Books-&gt;set_primary_key("id");</pre>
473    </div>
474
475    <div class="slide">
476       <h1>Schema::Loader</h1>
477 <pre>Foo::Schema::Result::Authors-&gt;has_many(books =&gt; "Foo::Schema::Books",
478    { "foreign.author" =&gt; "self.id" });
479
480 Foo::Schema::Result::Books-&gt;belongs_to(author =&gt; "Foo::Schema::Authors",
481    { id =&gt; "author" });</pre>
482    </div>
483
484    <div class="slide">
485       <h1>SQL - debugging</h1>
486 <pre>INSERT INTO authors (name)
487    VALUES (?): 'Douglas Adams'
488
489 INSERT INTO books (author, title)
490    VALUES (?, ?): '5', '42'</pre>
491    </div>
492
493    <div class="slide">
494       <h1>overloading</h1>
495 <pre>Foo::Schema::Result::Books
496 Foo::Schema::ResultSet::Books
497 Foo::Schema::Result::Authors
498 Foo::Schema::ResultSet::Books</pre>
499    </div>
500
501    <div class="slide">
502       <h1>Result::</h1>
503 <pre>package Foo::Schema::Result::Books;
504 use base 'DBIx::Class';
505 use strict;
506 use warnings;
507
508 sub isbn {
509    my $self = shift;
510
511    # search amazon or something
512    my $api = Amazon::API-&gt;book({
513       title =&gt; $self-&gt;title
514    });
515
516    return $api-&gt;isbn;
517 }
518
519 1;</pre>
520    </div>
521
522    <div class="slide">
523       <h1>Result::</h1>
524 <pre>print $book-&gt;isbn;</pre>
525    </div>
526
527    <div class="slide">
528       <h1>Result:: (inflating)</h1>
529 <pre>package Foo::Schema::Result::Books;
530 use base 'DBIx::Class';
531 use strict;
532 use warnings;
533
534 use DateTime::Format::MySQL;
535
536 __PACKAGE__-&gt;<strong>inflate_column</strong>(
537    <strong>date_published</strong> =&gt; {
538       inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
539       deflate =&gt; sub { shift-&gt;ymd},
540    }
541 );
542 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
543    </div>
544
545    <div class="slide">
546       <h1>Result:: (inflating)</h1>
547 <pre>package Foo::Schema::Result::Books;
548 use base 'DBIx::Class';
549 use strict;
550 use warnings;
551
552 use DateTime::Format::MySQL;
553
554 __PACKAGE__-&gt;inflate_column(
555    date_published =&gt; {
556       <strong>inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
557       deflate =&gt; sub { shift-&gt;ymd},</strong>
558    }
559 );
560 # Automatic see: DBIx::Class::InflateColumn::DateTime
561 # Automatic see: DBIx::Class::InflateColumn::DateTime
562 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
563    </div>
564
565    <div class="slide">
566       <h1>Result:: (deflating)</h1>
567 <pre>$book-&gt;date_published(DateTime-&gt;now);
568 $book-&gt;update;</pre>
569    </div>
570
571    <div class="slide">
572       <h1>Result:: (inflating)</h1>
573 <pre>my $date_published = $book-&gt;date_published;
574 print $date_published-&gt;month_abbr;</pre>
575
576 <strong><em>Nov</em></strong>
577    </div>
578
579    <div class="slide">
580       <h1>ResultSets::</h1>
581 <pre>package Foo::Schema::ResultSet::Books;
582 use base 'DBIx::Class::ResultSet';
583 sub the_ultimate_books {
584    my $self = shift;
585    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
586 }
587 sub by_author {
588    my ( $self, $author ) = @_;
589    return $self-&gt;search({ author =&gt; $author-&gt;id })
590 }
591
592 1;</pre>
593    </div>
594
595    <div class="slide">
596       <h1>ResultSets::</h1>
597 <pre>package Foo::Schema::<strong>ResultSet::Books</strong>;
598 use base '<strong>DBIx::Class::ResultSet</strong>';
599 sub the_ultimate_books {
600    my $self = shift;
601    <strong>return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } })</strong>
602 }
603 sub by_author {
604    my ( $self, $author ) = @_;
605    return $self-&gt;search({ author =&gt; $author-&gt;id })
606 }
607
608 1;</pre>
609    </div>
610
611    <div class="slide">
612       <h1>ResultSets::</h1>
613 <pre>package Foo::Schema::ResultSet::Books;
614 use base 'DBIx::Class::ResultSet';
615 sub the_ultimate_books {
616    my $self = shift;
617    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
618 }
619 sub by_author {
620    my ( $self, $author ) = @_;
621    <strong>return $self-&gt;search({ author =&gt; $author-&gt;id })</strong>
622 }
623
624 1;</pre>
625    </div>
626
627    <div class="slide">
628       <h1>ResultSets::</h1>
629 <pre>use Foo::Schema;
630 my $book_model = Foo::Schema-&gt;resultset('Books');
631 my $book_rs    = $book_model-&gt;the_ultimate_books;
632 my @books      = $book_rs-&gt;all;</pre>
633    </div>
634
635    <div class="slide">
636       <h1>ResultSets::chaining</h1>
637 <pre>use Foo::Schema;
638 my $book_model   = Foo::Schema-&gt;resultset('Books');
639 my $author_model = Foo::Schema-&gt;resultset('Authors');
640 my $author       = $author_model-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
641 my $book_rs      = $book_model-&gt;the_ultimate_books-&gt;by_author($author);
642 my @books        = $book_rs-&gt;all;</pre>
643    </div>
644
645    <div class="slide">
646       <h1>ResultSets::chaining</h1>
647 <pre>my $book_rs = $book_model
648   -&gt;the_ultimate_books
649   -&gt;by_author($author);</pre>
650 or
651
652 <pre>my $book_rs = $book_model
653   -&gt;the_ultimate_books();
654 $book_rs = $book_rs-&gt;by_author($author);</pre>
655 <pre># Debug (SQL):
656
657 # SELECT me.id, me.title, me.date_published, me.author
658 #   FROM books me
659 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
660 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre>
661    </div>
662
663    <div class="slide">
664       <h1>ResultSets::chaining</h1>
665 <pre>my $rs = $book_model
666   -&gt;category('childrens')
667   -&gt;by_author($author)
668   -&gt;published_after('1812')
669   -&gt;first_page_contains('once upon')
670   -&gt;rating_greater_than(4);
671
672 my @books = $rs-&gt;all;</pre>
673    </div>
674
675    <div class="slide">
676       <h1>overloading before new record</h1>
677    </div>
678
679    <div class="slide">
680       <h1>overloading before new record</h1>
681       <pre>package Foo::Schema::Result::Authors;
682 use base 'DBIx::Class';
683
684 sub new {
685    my ( $class, $attrs ) = @_;
686    # Mess with $attrs
687    my $new = $class-&gt;next::method($attrs);
688    return $new
689 }
690
691 1;</pre>
692
693    <div class="slide">
694       <h1>relationships</h1>
695    </div>
696
697    <div class="slide">
698       <h1>multiple authors</h1>
699    </div>
700
701    <div class="slide">
702       <h1>a few relationships</h1>
703       (authors -- author_link_to_book -- books)
704    </div>
705
706    <div class="slide">
707       <h1>a few relationships</h1>
708       !
709    </div>
710
711    <div class="slide">
712       <h1>new join table</h1>
713 <pre>CREATE TABLE author_and_books(
714   id      int(8)    primary key auto_increment,
715   book    int(8),
716   author  int(8),
717   foreign key (book)     references books(id),
718   foreign key (author)   references authors(id)
719 ) engine = InnoDB DEFAULT CHARSET=utf8;
720
721 ALTER TABLE `books` DROP `author`</pre>
722    </div>
723
724    <div class="slide">
725       <h1>new join table</h1>
726 <pre>CREATE TABLE author_and_books(
727   id      int(8)    primary key auto_increment,
728   book    int(8),
729   author  int(8),
730   <strong>foreign key (book)     references books(id),
731   foreign key (author)   references authors(id)</strong>
732 ) engine = InnoDB DEFAULT CHARSET=utf8;
733
734 ALTER TABLE `books` DROP `author`</pre>
735    </div>
736
737    <div class="slide">
738       <h1>has_many</h1>
739    </div>
740
741    <div class="slide">
742       <h1>has_many</h1>
743 <pre>package Foo::Schema::<strong>Result::Books</strong>;
744
745 __PACKAGE__-&gt;has_many( author_and_books =&gt; "Foo::Schema::Result::AuthorAndBooks",
746     { "foreign.book" =&gt; "self.id" },
747 );
748
749 <strong># This is auto generated by Schema::Loader</strong></pre>
750    </div>
751
752    <div class="slide">
753       <h1>has_many</h1>
754 <pre>package Foo::Schema::<strong>Result::Books</strong>;
755
756 __PACKAGE__-&gt;has_many(
757 author_and_books =&gt; <strong># name of accessor</strong>
758 "Foo::Schema::Result::AuthorAndBooks", <strong># related class</strong>
759     { "foreign.book" =&gt; "self.id" } <strong># Relationship (magic often works if not
760                                         # specified, but avoid!)</strong>
761 );
762 </pre>
763    </div>
764
765    <div class="slide">
766       <h1>belongs_to</h1>
767    </div>
768
769    <div class="slide">
770       <h1>belongs_to</h1>
771 <pre>package Foo::Schema::<strong>Result::AuthorAndBooks</strong>;
772
773 __PACKAGE__-&gt;belongs_to(
774    book =&gt; <strong># Accessor name</strong>
775    "Foo::Schema::Result::Books", <strong># Related class</strong>
776    { id =&gt; "book" } <strong># relationship</strong>
777 );
778 </pre>
779    </div>
780
781    <div class="slide">
782       <h1>same for Authors</h1>
783    </div>
784
785    <div class="slide">
786       <h1>with no coding...</h1>
787    </div>
788
789    <div class="slide">
790       <h1>many_to_many</h1>
791    </div>
792
793    <div class="slide">
794       <h1>many_to_many</h1>
795       <pre>package Foo::Schema::<strong>Result::Books</strong>;
796 use base 'DBIx::Class';
797
798 __PACKAGE__-&gt;many_to_many(
799    authors =&gt; "author_and_books", 'author'
800 );
801
802 1;
803
804 <strong> # This is <em>NOT</em> auto generated by Schema::Loader </strong></pre>
805    </div>
806
807    <div class="slide">
808       <h1>many_to_many</h1>
809       <pre>package Foo::Schema::<strong>Result::Books</strong>;
810 use base 'DBIx::Class';
811
812 __PACKAGE__-&gt;many_to_many(
813    authors <strong># Accessor name</strong>
814    =&gt; "author_and_books", <strong># has_many</strong>
815    'author' <strong># foreign relationship name</strong>
816 );
817
818 1;</pre>
819    </div>
820
821    <div class="slide">
822       <h1>many_to_many</h1>
823       <pre>package Foo::Schema::Result::Authors;
824 use base 'DBIx::Class';
825
826 __PACKAGE__-&gt;many_to_many(
827    "books" <strong># Accessor Name</strong>
828    =&gt; "author_and_books", <strong># has_many accessor_name</strong>
829    'book' <strong># foreign relationship name</strong>
830 );
831
832 1;
833
834 <strong># This is <em>NOT</em> auto generated by Schema::Loader</strong></pre>
835    </div>
836
837    <div class="slide">
838       <h1>using many_to_many</h1>
839       <pre>#!/usr/bin/perl
840
841 use Foo::Schema;
842
843 my $author_model = Foo::Schema-&gt;resultset('Authors');
844 my $author       = $author_model-&gt;search({
845    name =&gt; 'Douglas Adams',
846 })-&gt;single;
847 $author-&gt;add_to_books({
848    title =&gt; 'A new book',
849 });</pre>
850    </div>
851
852    <div class="slide">
853       <h1>using many_to_many</h1>
854       <pre>my $author = $author_model-&gt;search({
855    name =&gt; 'Douglas Adams',
856 })-&gt;single;
857 <strong>$author-&gt;add_to_books({
858    title =&gt; 'A new book',
859 });</strong>
860
861 # SELECT me.id, me.name FROM authors me
862 #     WHERE ( name = ? ): 'Douglas Adams';
863 # INSERT INTO books (title) VALUES (?): 'A new book';
864 # INSERT INTO author_and_books (author, book)
865 #     VALUES (?, ?): '5', '2';</pre>
866    </div>
867
868    <div class="slide">
869       <h1>using many_to_many</h1>
870       <pre>$author-&gt;add_to_books($book);
871
872 $book-&gt;add_to_authors($author_1);
873 $book-&gt;add_to_authors($author_2);</pre>
874    </div>
875
876    <div class="slide">
877       <h1>in 16 lines of code</h1>
878    </div>
879
880    <div class="slide">
881       <h1>errors</h1>
882       <p>Read them closely!</p>
883    </div>
884
885    <div class="slide">
886       <h1>error messages</h1>
887       <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>
888    </div>
889
890    <div class="slide">
891       <h1>error messages</h1>
892    <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>
893    </div>
894
895    <div class="slide">
896       <h1>errors</h1>
897       <ul>
898          <li>Turn on debugging</li>
899          <li>Read error messages (sometimes useful!)</li>
900          <li>Check field names</li>
901          <li>Check package names</li>
902          <li>Check which database you are connected to (dev/test/live?) - repeat above</li>
903       </ul>
904    </div>
905
906    <div class="slide">
907       <h1>bonus slides!</h1>
908    </div>
909
910    <div class="slide">
911       <h1>Template Toolkit</h1>
912       <ul>
913          <li><pre>[% author.books.count %]</pre> not working?</li>
914          <li>TT all methods are called in list context</li>
915          <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li>
916          <li><em>Available for all relationships</em></li>
917       </ul>
918    </div>
919
920    <div class="slide">
921       <h1>Catalyst</h1>
922       <pre>package Your::App::Model::<strong>Foo</strong>;
923 use base qw(<strong>Catalyst::Model::Schema::Schema</strong>);
924
925 use strict;
926 use warnings;
927
928 __PACKAGE__-&gt;config(
929   schema_class =&gt; '<strong>Foo::Schema</strong>',
930 );
931
932 1;</pre>
933    <p>Keep your Schema in a <em>separate</em> package to your Catalyst application</p>
934    </div>
935
936    <div class="slide">
937       <h1>Catalyst</h1>
938 <pre>sub action_name : Local {
939   my ($self, $c) = @_;
940
941   my $model = $c-&gt;model('Schema::Foo');
942   my $author_model = $model-&gt;resultset('Authors');
943
944 }
945
946 1;</pre>
947    </div>
948
949 </div>
950 </body>
951 </html>