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