images and some more deets
[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 Foo::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    'Foo::Schema::Result::Book', 'author_id'
362 );
363 1;
364 </pre>
365    </div>
366
367    <div class="slide">
368 <pre>package Foo::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    'Foo::Schema::Result::Author', 'author_id'
390 );
391 1;
392 </pre>
393    </div>
394
395    <div class="slide">
396       <h1>-&gt;deploy</h1>
397       <p>Perl -&gt; DB</p>
398 <pre>my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
399 $schema-&gt;deploy
400 </pre>
401 <p>See also: <a href="http://search.cpan.org/perldoc?DBIx::Class::DeploymentHandler">DBIx::Class::DeploymentHandler</a></p>
402    </div>
403
404    <div class="slide">
405       <h1>Schema::Loader</h1>
406       <p>DB -&gt; Perl</p>
407 <pre>package Foo::Schema;
408 use strict; use warnings;
409 use base 'DBIx::Class::Schema::Loader';
410 __PACKAGE__-&gt;loader_options({
411    naming =&gt; 'v7',
412    debug  =&gt; $ENV{DBIC_TRACE},
413 });
414 1;
415
416 # elsewhere...
417
418 my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
419 </pre>
420    </div>
421
422    <div class="slide">
423       <h1>Splitting Logic Cleanly</h1>
424       <p>Foo::Schema::Result::Bar = individual row</p>
425       <p>Foo::Schema::ResultSet::Bar = searches / table </p>
426    </div>
427
428    <div class="slide">
429       <h1>Using your Schema</h1>
430 <pre>#!perl
431 use strict; use warnings;
432 use lib 'lib';
433 use Foo::Schema;
434 my $schema = Foo::Schema-&gt;connect($dns, $user, $pass);
435 my $author_rs = $schema-&gt;resultset('Author');
436 my $author    = $author_rs-&gt;create({
437    name =&gt; 'Douglas Adams',
438 });
439 my $book = $author-&gt;add_to_books({
440    title =&gt; '42',
441 });
442 </pre>
443    </div>
444
445    <div class="slide">
446       <h1>DEBUGGING</h1>
447       <pre>DBIC_TRACE=1 ./your_script.pl</pre>
448    </div>
449
450    <div class="slide">
451       <h1>SQL - debugging</h1>
452 <pre>INSERT INTO authors (name)
453    VALUES (?): 'Douglas Adams'
454
455 INSERT INTO books (author, title)
456    VALUES (?, ?): '5', '42'</pre>
457    </div>
458
459    <div class="slide">
460       <h1>overloading</h1>
461 <pre>Foo::Schema::Result::Book
462 Foo::Schema::ResultSet::Book
463 Foo::Schema::Result::Author
464 Foo::Schema::ResultSet::Book</pre>
465    </div>
466
467    <div class="slide">
468       <h1>Result::</h1>
469 <pre>package Foo::Schema::Result::Book;
470 use base 'DBIx::Class::Core';
471 use strict;
472 use warnings;
473
474 # Result code here
475
476 sub isbn {
477    my $self = shift;
478
479    # search amazon or something
480    my $api = Amazon::API-&gt;book({
481       title =&gt; $self-&gt;title
482    });
483
484    return $api-&gt;isbn;
485 }
486
487 1;</pre>
488    </div>
489
490    <div class="slide">
491       <h1>Result::</h1>
492 <pre>print $book-&gt;isbn;</pre>
493    </div>
494
495    <div class="slide">
496       <h1>Result:: (inflating)</h1>
497 <pre>package Foo::Schema::Result::Book;
498 use base 'DBIx::Class::Core';
499 use strict;
500 use warnings;
501
502 # Result code here
503
504 __PACKAGE__-&gt;load_components('InflateColumn');
505 use DateTime::Format::MySQL;
506
507 __PACKAGE__-&gt;<strong>inflate_column</strong>(
508    <strong>date_published</strong> =&gt; {
509       inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
510       deflate =&gt; sub { shift-&gt;ymd},
511    },
512 );
513 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
514    </div>
515
516    <div class="slide">
517       <h1>Result:: (deflating)</h1>
518 <pre>$book-&gt;date_published(DateTime-&gt;now);
519 $book-&gt;update;</pre>
520    </div>
521
522    <div class="slide">
523       <h1>Result:: (inflating)</h1>
524 <pre>my $date_published = $book-&gt;date_published;
525 print $date_published-&gt;month_abbr;</pre>
526
527 <strong><em>Nov</em></strong>
528    </div>
529
530    <div class="slide">
531       <h1>ResultSets::</h1>
532 <pre>package Foo::Schema::ResultSet::Books;
533 use base 'DBIx::Class::ResultSet';
534 sub the_ultimate_books {
535    my $self = shift;
536    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
537 }
538 sub by_author {
539    my ( $self, $author ) = @_;
540    return $self-&gt;search({ author =&gt; $author-&gt;id })
541 }
542
543 1;</pre>
544    </div>
545
546    <div class="slide">
547       <h1>ResultSets::</h1>
548 <pre>use Foo::Schema;
549 my $schema = Foo::Schema-&gt;connect(...);
550 my $book_rs     = Foo::Schema-&gt;resultset('Book');
551 my $book_search = $book_rs-&gt;the_ultimate_books;
552 my @books       = $book_search-&gt;all;</pre>
553    </div>
554
555    <div class="slide">
556       <h1>ResultSets: Chaining</h1>
557 <pre>
558 my $book_rs      = $schema-&gt;resultset('Book');
559 my $author_rs    = $schema-&gt;resultset('Author');
560 my $author       = $author_model-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
561 my $book_rs      = $book_model-&gt;the_ultimate_books-&gt;by_author($author);
562 my @books        = $book_rs-&gt;all;</pre>
563    </div>
564
565    <div class="slide">
566       <h1>ResultSets: Chaining</h1>
567 <pre>$book_rs = $schema-&gt;resultset('Book')
568   -&gt;the_ultimate_books
569   -&gt;by_author($author);</pre>
570 or
571
572 <pre>my $book_rs = $schema-&gt;resultset('Book')
573   -&gt;the_ultimate_books;
574 $book_rs = $book_rs-&gt;by_author($author);</pre>
575 <pre># Debug (SQL):
576
577 # SELECT me.id, me.title, me.date_published, me.author
578 #   FROM books me
579 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
580 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre>
581    </div>
582
583    <div class="slide">
584       <h1>ResultSets::chaining</h1>
585 <pre>my $rs = $book_model
586   -&gt;category('childrens')
587   -&gt;by_author($author)
588   -&gt;published_after('1812')
589   -&gt;first_page_contains('once upon')
590   -&gt;rating_greater_than(4);
591
592 my @books = $rs-&gt;all;</pre>
593    </div>
594
595    <div class="slide">
596       <h1>overloading before new record</h1>
597       <pre>package Foo::Schema::Result::Author;
598 use base 'DBIx::Class::Core';
599
600 sub new {
601    my ( $class, $attrs ) = @_;
602    # Mess with $attrs
603    my $new = $class-&gt;next::method($attrs);
604    return $new
605 }
606
607 1;</pre>
608
609    <div class="slide">
610       <h1>Relationships</h1>
611    </div>
612
613    <div class="slide">
614       <h1>Multiple Authors</h1>
615    </div>
616
617    <div class="slide">
618       <h1>a few relationships</h1>
619       <img src="img/afewrels.png" />
620    </div>
621
622    <div class="slide">
623       <h1>Join Table</h1>
624 <pre>CREATE TABLE author_and_books(
625   book_id    int(8),
626   author_id  int(8),
627   foreign key (book_id)     references books(id),
628   foreign key (author_id)   references authors(id)
629 ) engine = InnoDB DEFAULT CHARSET=utf8;
630
631 ALTER TABLE `books` DROP `author`;</pre>
632    </div>
633
634    <div class="slide">
635       <h1>has_many</h1>
636       <img src="img/hasmany1.png" />
637    </div>
638
639    <div class="slide">
640       <h1>has_many</h1>
641 <pre>package Foo::Schema::<strong>Result::Book</strong>;
642
643 __PACKAGE__-&gt;has_many( author_and_books =&gt;
644    'Foo::Schema::Result::Author_Book', 'book_id'
645 );
646    </div>
647
648    <div class="slide">
649       <h1>belongs_to</h1>
650       <img src="img/belongsto1.png" />
651    </div>
652
653    <div class="slide">
654       <h1>belongs_to</h1>
655 <pre>package Foo::Schema::<strong>Result::Author_Book</strong>;
656
657 __PACKAGE__-&gt;belongs_to(
658    book =&gt;
659    'Foo::Schema::Result::Book', 'book_id'
660 );
661 </pre>
662    </div>
663
664    <div class="slide">
665       <h1>same for Authors</h1>
666       <img src="img/authors.png" />
667    </div>
668
669    <div class="slide">
670       <h1>many_to_many</h1>
671       <img src="img/m2m.png" />
672    </div>
673
674    <div class="slide">
675       <h1>many_to_many</h1>
676       <pre>package Foo::Schema::<strong>Result::Book</strong>;
677 use base 'DBIx::Class::Core';
678
679 __PACKAGE__-&gt;many_to_many(
680    authors =&gt; 'author_and_books', 'author'
681 );
682
683 1;
684 </pre>
685    </div>
686
687    <div class="slide">
688       <h1>many_to_many</h1>
689       <pre>package Foo::Schema::<strong>Result::Book</strong>;
690 use base 'DBIx::Class::Core';
691
692 __PACKAGE__-&gt;many_to_many(
693    authors <strong># Accessor name</strong>
694    =&gt; "author_and_books", <strong># has_many</strong>
695    'author' <strong># foreign relationship name</strong>
696 );
697
698 1;</pre>
699    </div>
700
701    <div class="slide">
702       <h1>many_to_many</h1>
703       <pre>package Foo::Schema::Result::Author;
704 use base 'DBIx::Class::Core';
705
706 __PACKAGE__-&gt;many_to_many(
707    "books" <strong># Accessor Name</strong>
708    =&gt; "author_and_books", <strong># has_many accessor_name</strong>
709    'book' <strong># foreign relationship name</strong>
710 );
711
712 1;
713 </pre>
714    </div>
715
716    <div class="slide">
717       <h1>Using many_to_many</h1>
718       <pre>#!perl
719 use Foo::Schema;
720 my $schema    = Foo::Schema-&gt;connect(...);
721 my $author_rs = $schema-&gt;resultset('Authors');
722 my $author    = $author_model-&gt;search({
723    name =&gt; 'Douglas Adams',
724 })-&gt;single;
725 $author-&gt;add_to_books({
726    title =&gt; 'A new book',
727 });</pre>
728    </div>
729
730    <div class="slide">
731       <h1>using many_to_many</h1>
732       <pre>my $author = $author_model-&gt;search({
733    name =&gt; 'Douglas Adams',
734 })-&gt;single;
735 <strong>$author-&gt;add_to_books({
736    title =&gt; 'A new book',
737 });</strong>
738
739 # SELECT me.id, me.name FROM authors me
740 #     WHERE ( name = ? ): 'Douglas Adams';
741 # INSERT INTO books (title) VALUES (?): 'A new book';
742 # INSERT INTO author_and_books (author, book)
743 #     VALUES (?, ?): '5', '2';</pre>
744    </div>
745
746    <div class="slide">
747       <h1>using many_to_many</h1>
748       <pre>$author-&gt;add_to_books($book);
749
750 $book-&gt;add_to_authors($author_1);
751 $book-&gt;add_to_authors($author_2);</pre>
752    </div>
753
754    <div class="slide">
755       <h1>errors</h1>
756       <p>Read them closely!</p>
757    </div>
758
759    <div class="slide">
760       <h1>error messages</h1>
761       <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>
762    </div>
763
764    <div class="slide">
765       <h1>error messages</h1>
766    <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>
767    </div>
768
769    <div class="slide">
770       <h1>errors</h1>
771       <ul>
772          <li>Turn on debugging</li>
773          <li>Read error messages (sometimes useful!)</li>
774          <li>Check field names</li>
775          <li>Check package names</li>
776          <li>Check which database you are connected to (dev/test/live?) - repeat above</li>
777       </ul>
778    </div>
779
780    <div class="slide">
781       <h1>LOTS more Features</h1>
782       <ul>
783          <li>FilterColumn</li>
784          <li>Transactions</li>
785          <li>HashRefInflator</li>
786          <li>Subqueries</li>
787          <li>ResultSetColumn</li>
788       </ul>
789    </div>
790
791    <div class="slide">
792       <h1>bonus slides!</h1>
793    </div>
794
795    <div class="slide">
796       <h1>Template Toolkit</h1>
797       <ul>
798          <li><pre>[% author.books.count %]</pre> not working?</li>
799          <li>TT all methods are called in list context</li>
800          <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li>
801          <li><em>Available for all relationships</em></li>
802       </ul>
803    </div>
804
805    <div class="slide">
806       <h1>Catalyst</h1>
807       <pre>package Your::App::Model::<strong>Foo</strong>;
808 use base qw(<strong>Catalyst::Model::Schema::Schema</strong>);
809
810 use strict;
811 use warnings;
812
813 __PACKAGE__-&gt;config(
814   schema_class =&gt; '<strong>Foo::Schema</strong>',
815 );
816
817 1;</pre>
818    <p>Keep your Schema in a <em>separate</em> package to your Catalyst application</p>
819    </div>
820
821    <div class="slide">
822       <h1>Catalyst</h1>
823 <pre>sub action_name : Local {
824   my ($self, $c) = @_;
825
826   my $model = $c-&gt;model('Schema::Foo');
827   my $author_model = $model-&gt;resultset('Authors');
828
829 }
830
831 1;</pre>
832    </div>
833
834 </div>
835 </body>
836 </html>