major additions for new orientation of presentation
[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>Amiri Barksdale</h4>
80       <h4>Justin D. Hunter</h4>
81       <h4>Arthur Axel "fREW" Schmidt</h4>
82    </div>
83
84    <div class="slide">
85       <h1>What's up guys?</h1>
86       <div class="notes">
87          <ul>
88             <li>How many people have used any ORM?<ul>
89                <li>In Perl?<ul>
90                   <li>DBIC?</li>
91                   <li>Class::DBI?</li>
92                   <li>Rose::DB?</li>
93                   <li>Fey?</li>
94                   <li>Others?</li>
95                </ul></li>
96                <li>AR?</li>
97                <li>DataMapper?</li>
98                <li>(N)Hibernate?</li>
99             </ul></li>
100          </ul>
101       </div>
102    </div>
103
104    <div class="slide">
105       <h1>Purpose</h1>
106       <p>The purpose of this talk is to show you as many features of
107       DBIx::Class in 40 minutes so that when you need to do something with
108       it later you will know what's possible</p>
109    </div>
110
111    <div class="slide">
112       <h1>DBIx::Class?</h1>
113       <ul>
114          <li>ORM (object relational mapper)</li>
115          <li>SQL &lt;-&gt; OO (using objects instead of SQL)</li>
116          <li>There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)</li>
117       </ul>
118    </div>
119
120    <div class="slide">
121       <h1>Meta</h1>
122       <p>These are reasons that are not technical or inherent to
123       the code of DBIC, but are totally awesome things about it.</p>
124    </div>
125
126    <div class="slide">
127       <h1>Large Community</h1>
128       <p>Currently there are 88 people listed as contributors to DBIC.  That
129       ranges from documentation help, to test help, to added features,
130       to entire database support.</p>
131    </div>
132
133    <div class="slide">
134       <h1>Active Community</h1>
135       <p>Currently (June 9, 2010) 6 active branches (commited to in the last two weeks) in git.  Last release (0.08122) had 14 new features, and 16 bug fixes.  Of course that <a href="http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git;a=blob;f=Changes">ebbs and flows</a>.</p>
136    </div>
137
138    <div class="slide">
139       <h1>Responsive Community</h1>
140       <ul class="incremental">
141          <li>needed MSSQL Order by support, they helped me add support</li>
142          <li>generally very welcoming of people willing to help</li>
143       </ul>
144    </div>
145
146    <div class="slide">
147       <h1>General ORM</h1>
148       <p>These are things that are in most other ORMs, but are still reasons
149       to use DBIC over raw SQL.</p>
150    </div>
151
152    <div class="slide">
153       <h1>Cross DB</h1>
154       <p>The vast majority of code should run on all databases without needing tweaking</p>
155    </div>
156
157    <div class="slide">
158       <h1>Basic CRUD</h1>
159       <ul class="incremental">
160          <li><strong>C</strong> - Create</li>
161          <li><strong>R</strong> - Read</li>
162          <li><strong>U</strong> - Update</li>
163          <li><strong>D</strong> - Delete</li>
164       </ul>
165    </div>
166
167    <div class="slide">
168       <h1>SQL: Create</h1>
169 <pre>my $sth = $dbh-&gt;prepare('
170    INSERT INTO books
171    (title, author_id)
172    values (?,?)
173 ');
174
175 $sth-&gt;execute(
176   'A book title', $author_id
177 );</pre>
178    </div>
179
180    <div class="slide">
181       <h1>DBIC: Create</h1>
182 <pre>my $book = $book_rs-&gt;create({
183    title     =&gt; 'A book title',
184    author_id =&gt; $author_id,
185 });</pre>
186       <ul class="incremental">
187          <li>No need to pair placeholders and values</li>
188       </ul>
189    </div>
190
191    <div class="slide">
192       <h1>SQL: Read</h1>
193 <pre>my $sth = $dbh-&gt;prepare('
194    SELECT title,
195    authors.name as author_name
196    FROM books, authors
197    WHERE books.author = authors.id
198 ');</pre>
199    </div>
200
201    <div class="slide">
202       <h1>SQL: Read</h1>
203 <pre>while( my $book = $sth-&gt;fetchrow_hashref() ) {
204   print 'Author of '
205      . $book-&gt;{title}
206      . ' is '
207      . $book-&gt;{author_name}
208      . "\n";
209 }</pre>
210    </div>
211
212    <div class="slide">
213       <h1>DBIC: Read</h1>
214 <pre>my $book = $book_rs-&gt;find($book_id);
215
216 my $book = $book_rs-&gt;search({
217    title =&gt; 'A book title',
218 }, { rows =&gt; 1 })-&gt;single;
219
220 my @books = $book_rs-&gt;search({
221    author =&gt; $author_id,
222 })-&gt;all;</pre>
223       <ul class="incremental">
224          <li>TMTOWTDI</li>
225       </ul>
226    </div>
227
228    <div class="slide">
229       <h1>DBIC: Read</h1>
230 <pre>while( my $book = $books_rs-&gt;next ) {
231  print 'Author of '
232     . $book-&gt;title
233     . ' is '
234     . $book-&gt;author-&gt;name
235     . "\n";
236 }</pre>
237    </div>
238
239    <div class="slide">
240       <h1>SQL: Update</h1>
241 <pre>my $update = $dbh-&gt;prepare('
242    UPDATE books
243    SET title = ?
244    WHERE id = ?
245 ');
246
247 $update-&gt;execute(
248   'New title',<strong>$book_id</strong>
249 );</pre>
250    </div>
251
252    <div class="slide">
253       <h1>DBIC: Update</h1>
254 <pre>$book-&gt;update({
255   title =&gt; 'New title',
256 });</pre>
257    </div>
258
259    <div class="slide">
260       <h1>SQL: Delete</h1>
261 <pre>my $delete = $dbh-&gt;prepare('
262    DELETE FROM books
263    WHERE id = ?
264 ');
265
266 $delete-&gt;execute(<strong>$book_id</strong>);</pre>
267    </div>
268
269    <div class="slide">
270       <h1>DBIC: Delete</h1>
271 <pre>$book-&gt;delete;</pre>
272    </div>
273
274    <div class="slide">
275       <h1>OO Overidability</h1>
276       <ul class="incremental">
277          <li>Override new if you want to do validation</li>
278          <li>Override delete if you want to disable deletion</li>
279          <li>and on and on</li>
280       </ul>
281       <div class="notes">
282          <p>I got yelled at about this before by people, so
283          we don't get EVERYTHING from OO, but we do get a lot
284          so :-P</p>
285       </div>
286    </div>
287
288    <div class="slide">
289       <h1>Convenience Methods</h1>
290       <ul class="incremental">
291          <li>find_or_create</li>
292          <li>create_or_update</li>
293       </ul>
294    </div>
295
296    <div class="slide">
297       <h1>Non-column methods</h1>
298       <p>Need a method to get a user's gravatar URL?  Add a
299       gravatar_url method to their Result class</p>
300    </div>
301
302    <div class="slide">
303       <h1>RELATIONSHIPS</h1>
304       <ul class="incremental">
305          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#belongs_to">belongs_to</a></li>
306          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#has_many">has_many</a></li>
307          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#might_have">might_have</a></li>
308          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#has_one">has_one</a></li>
309          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#many_to_many">many_to_many</a> (technically not a relationship)</li>
310          <li>SET AND FORGET</li>
311       </ul>
312    </div>
313
314    <div class="slide">
315       <h1>DBIx::Class Specific Features</h1>
316       <p>These things may be in other ORM's, but they are very specific, so doubtful</p>
317    </div>
318
319    <div class="slide">
320       <h1>-&gt;deploy</h1>
321       <p>Perl -&gt; DB</p>
322 <pre>my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
323 $schema-&gt;deploy
324 </pre>
325 <p>See also: <a href="http://search.cpan.org/perldoc?DBIx::Class::DeploymentHandler">DBIx::Class::DeploymentHandler</a></p>
326    </div>
327
328    <div class="slide">
329       <h1>Schema::Loader</h1>
330       <p>DB -&gt; Perl</p>
331 <pre>package Foo::Schema;
332 use strict; use warnings;
333 use base 'DBIx::Class::Schema::Loader';
334 __PACKAGE__-&gt;loader_options({
335    naming =&gt; 'v7',
336    debug  =&gt; $ENV{DBIC_TRACE},
337 });
338 1;
339
340 # elsewhere...
341
342 my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
343 </pre>
344    </div>
345
346    <div class="slide">
347       <h1>Populate</h1>
348       <p>Made for inserting lots of rows very quicky into database</p>
349 <pre>$schema-&gt;populate([ Users =&gt;
350    [qw( username password )],
351    [qw( frew &gt;=4char$  )],
352    [qw(      ...          )],
353    [qw(      ...          )],
354 );
355 </pre>
356       <ul class="incremental">
357          <li>I use this to <a href="http://blog.afoolishmanifesto.com/archives/1255">export our whole (200M~) db to SQLite</a></li>
358       </ul>
359    </div>
360
361    <div class="slide">
362       <h1>Multicreate</h1>
363       <p>Create an object and all of it's related objects all at once</p>
364 <pre>$schema-&gt;resultset('Author')-&gt;create({
365    name =&gt; 'Stephen King',
366    books =&gt; [{ title =&gt; 'The Dark Tower' }],
367    address =&gt; {
368       street =&gt; '123 Turtle Back Lane',
369       state  =&gt; { abbreviation =&gt; 'ME' },
370       city   =&gt; { name =&gt; 'Lowell' },
371    },
372 </pre>
373       <div class="notes">
374          <ul>
375             <li>books is a has_many</li>
376             <li>address is a belongs_to which in turn belongs to state and city each</li>
377             <li>for this to work right state and city must mark abbreviation and name as unique</li>
378          </ul>
379       </div>
380    </div>
381
382    <div class="slide">
383       <h1>Extensible</h1>
384       <p>DBIx::Class helped pioneer fast MI in Perl 5 with Class::C3, so it is made
385       to allow extensions to nearly every part of it.</p>
386    </div>
387
388    <div class="slide">
389       <h1>Extensible: DBIC::Helpers</h1>
390       <ul class="incremental">
391          <li>DBIx::Class::Helper::ResultSet::IgnoreWantarray</li>
392          <li>DBIx::Class::Helper::ResultSet::Random</li>
393          <li>DBIx::Class::Helper::ResultSet::SetOperations</li>
394          <li>DBIx::Class::Helper::Row::JoinTable</li>
395          <li>DBIx::Class::Helper::Row::NumifyGet</li>
396          <li>DBIx::Class::Helper::Row::SubClass</li>
397          <li>DBIx::Class::Helper::Row::ToJSON</li>
398       </ul>
399    </div>
400
401    <div class="slide">
402       <h1>Extensible: DBIC::TimeStamp</h1>
403       <ul class="incremental">
404          <li>Cross DB</li>
405          <li>set_on_create</li>
406          <li>set_on_update</li>
407       </ul>
408    </div>
409
410    <div class="slide">
411       <h1>Extensible: DBIx::Class::Schema::KiokuDB</h1>
412       <ul class="incremental">
413          <li>Kioku is the new hotness</li>
414          <li>Mix RDBMS with Object DB</li>
415          <li>beta ( == sexy )</li>
416       </ul>
417    </div>
418
419    <div class="slide">
420       <h1>SQL::Abstract</h1>
421       <pre>my $resultset = $book_rs-&gt;search({
422          name =&gt; { -like =&gt; "%$nick%" },
423       });</pre>
424       <ul class="incremental">
425          <li>(kinda) introspectible</li>
426          <li>Prettier than SQL</li>
427       </ul>
428    </div>
429
430    <div class="slide">
431       <h1>Result vs ResultSet</h1>
432          <ul class="incremental">
433             <li>Result == Row</li>
434             <li>ResultSet == Query</li>
435             <li>(less important but...)</li>
436             <li>ResultSource == Table</li>
437             <li>Storage == Database</li>
438          </ul>
439    </div>
440
441    <div class="slide">
442       <h1>ResultSet methods</h1>
443 <pre>package MyApp::Schema::ResultSet::Book;
444 use base 'DBIx::Class::ResultSet';
445 sub good {
446    my $self = shift;
447    $self-&gt;search({
448       rating =&gt; { '&gt;=' =&gt; 4 },
449    })
450 };
451 sub cheap {
452    my $self = shift;
453    $self-&gt;search({
454       price =&gt; { '&lt;=' =&gt; 5}
455    })
456 };
457 # ...
458 1;
459       </pre>
460       <ul class="incremental">
461          <li>All searches should be ResultSet methods</li>
462          <li>Name has obvious meaning</li>
463       </ul>
464    </div>
465
466    <div class="slide">
467       <h1>ResultSet method in Action</h1>
468       <pre>$schema-&gt;resultset('Book')-&gt;good</pre>
469    </div>
470
471    <div class="slide">
472       <h1>ResultSet Chaining</h1>
473 <pre>$schema-&gt;resultset('Book')
474    -&gt;good
475    -&gt;cheap
476    -&gt;recent
477 </pre>
478    </div>
479
480    <div class="slide">
481       <h1>DEBUGGING</h1>
482       <pre>DBIC_TRACE=1 ./your_script.pl</pre>
483    </div>
484
485    <div class="slide">
486       <h1>SQL - debugging</h1>
487 <pre>INSERT INTO authors (name)
488    VALUES (?): 'Douglas Adams'
489
490 INSERT INTO books (author, title)
491    VALUES (?, ?): '5', '42'</pre>
492    </div>
493
494    <div class="slide">
495       <h1>overloading</h1>
496 <pre>Foo::Schema::Result::Book
497 Foo::Schema::ResultSet::Book
498 Foo::Schema::Result::Author
499 Foo::Schema::ResultSet::Book</pre>
500    </div>
501
502    <div class="slide">
503       <h1>Result::</h1>
504 <pre>package Foo::Schema::Result::Book;
505 use base 'DBIx::Class::Core';
506 use strict;
507 use warnings;
508
509 # Result code here
510
511 sub isbn {
512    my $self = shift;
513
514    # search amazon or something
515    my $api = Amazon::API-&gt;book({
516       title =&gt; $self-&gt;title
517    });
518
519    return $api-&gt;isbn;
520 }
521
522 1;</pre>
523    </div>
524
525    <div class="slide">
526       <h1>Result::</h1>
527 <pre>print $book-&gt;isbn;</pre>
528    </div>
529
530    <div class="slide">
531       <h1>Result:: (inflating)</h1>
532 <pre>package Foo::Schema::Result::Book;
533 use base 'DBIx::Class::Core';
534 use strict;
535 use warnings;
536
537 # Result code here
538
539 __PACKAGE__-&gt;load_components('InflateColumn');
540 use DateTime::Format::MySQL;
541
542 __PACKAGE__-&gt;<strong>inflate_column</strong>(
543    <strong>date_published</strong> =&gt; {
544       inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
545       deflate =&gt; sub { shift-&gt;ymd},
546    },
547 );
548 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
549    </div>
550
551    <div class="slide">
552       <h1>Result:: (deflating)</h1>
553 <pre>$book-&gt;date_published(DateTime-&gt;now);
554 $book-&gt;update;</pre>
555    </div>
556
557    <div class="slide">
558       <h1>Result:: (inflating)</h1>
559 <pre>my $date_published = $book-&gt;date_published;
560 print $date_published-&gt;month_abbr;</pre>
561
562 <strong><em>Nov</em></strong>
563    </div>
564
565    <div class="slide">
566       <h1>ResultSets::</h1>
567 <pre>package Foo::Schema::ResultSet::Books;
568 use base 'DBIx::Class::ResultSet';
569 sub the_ultimate_books {
570    my $self = shift;
571    return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
572 }
573 sub by_author {
574    my ( $self, $author ) = @_;
575    return $self-&gt;search({ author =&gt; $author-&gt;id })
576 }
577
578 1;</pre>
579    </div>
580
581    <div class="slide">
582       <h1>ResultSets::</h1>
583 <pre>use Foo::Schema;
584 my $schema = Foo::Schema-&gt;connect(...);
585 my $book_rs     = Foo::Schema-&gt;resultset('Book');
586 my $book_search = $book_rs-&gt;the_ultimate_books;
587 my @books       = $book_search-&gt;all;</pre>
588    </div>
589
590    <div class="slide">
591       <h1>ResultSets: Chaining</h1>
592 <pre>
593 my $book_rs   = $schema-&gt;resultset('Book');
594 my $author_rs = $schema-&gt;resultset('Author');
595 my $author    = $author_rs-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
596 $book_rs      = $book_rs-&gt;the_ultimate_books-&gt;by_author($author);
597 my @books     = $book_rs-&gt;all;</pre>
598    </div>
599
600    <div class="slide">
601       <h1>ResultSets: Chaining</h1>
602 <pre>$book_rs = $schema-&gt;resultset('Book')
603   -&gt;the_ultimate_books
604   -&gt;by_author($author);</pre>
605 or
606
607 <pre>my $book_rs = $schema-&gt;resultset('Book')
608   -&gt;the_ultimate_books;
609 $book_rs = $book_rs-&gt;by_author($author);</pre>
610 <pre># Debug (SQL):
611
612 # SELECT me.id, me.title, me.date_published, me.author
613 #   FROM books me
614 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
615 #   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre>
616    </div>
617
618    <div class="slide">
619       <h1>ResultSets: Chaining</h1>
620 <pre>my $rs = $book_rs
621   -&gt;category('childrens')
622   -&gt;by_author($author)
623   -&gt;published_after('1812')
624   -&gt;first_page_contains('once upon')
625   -&gt;rating_greater_than(4);
626
627 my @books = $rs-&gt;all;</pre>
628    </div>
629
630    <div class="slide">
631       <h1>overloading before new record</h1>
632       <pre>package Foo::Schema::Result::Author;
633 use base 'DBIx::Class::Core';
634
635 sub new {
636    my ( $class, $attrs ) = @_;
637    # Mess with $attrs
638    my $new = $class-&gt;next::method($attrs);
639    return $new
640 }
641
642 1;</pre>
643
644    <div class="slide">
645       <h1>Relationships</h1>
646    </div>
647
648    <div class="slide">
649       <h1>Multiple Authors</h1>
650       <p>We want to allow a book to be by more than one author</p>
651    </div>
652
653    <div class="slide">
654       <h1>a few relationships</h1>
655       <img src="img/afewrels.png" />
656    </div>
657
658    <div class="slide">
659       <h1>Join Table</h1>
660 <pre>CREATE TABLE author_and_books(
661   book_id    int(8),
662   author_id  int(8),
663   foreign key (book_id)     references books(id),
664   foreign key (author_id)   references authors(id)
665 ) engine = InnoDB DEFAULT CHARSET=utf8;
666
667 ALTER TABLE `books` DROP `author_id`;</pre>
668    </div>
669
670    <div class="slide">
671       <h1>has_many</h1>
672       <img src="img/hasmany1.png" />
673    </div>
674
675    <div class="slide">
676       <h1>has_many</h1>
677 <pre>package Foo::Schema::<strong>Result::Book</strong>;
678
679 __PACKAGE__-&gt;has_many( author_and_books =&gt;
680    'Foo::Schema::Result::Author_Book', 'book_id'
681 );
682    </div>
683
684    <div class="slide">
685       <h1>belongs_to</h1>
686       <img src="img/belongsto1.png" />
687    </div>
688
689    <div class="slide">
690       <h1>belongs_to</h1>
691 <pre>package Foo::Schema::<strong>Result::Author_Book</strong>;
692
693 __PACKAGE__-&gt;belongs_to(
694    book =&gt;
695    'Foo::Schema::Result::Book', 'book_id'
696 );
697 </pre>
698    </div>
699
700    <div class="slide">
701       <h1>same for Authors</h1>
702       <img src="img/authors.png" />
703    </div>
704
705    <div class="slide">
706       <h1>many_to_many</h1>
707       <img src="img/m2m.png" />
708    </div>
709
710    <div class="slide">
711       <h1>many_to_many</h1>
712       <pre>package Foo::Schema::<strong>Result::Book</strong>;
713 use base 'DBIx::Class::Core';
714
715 __PACKAGE__-&gt;many_to_many(
716    authors =&gt; 'author_and_books', 'author'
717 );
718
719 1;
720 </pre>
721    </div>
722
723    <div class="slide">
724       <h1>many_to_many</h1>
725       <pre>package Foo::Schema::<strong>Result::Book</strong>;
726 use base 'DBIx::Class::Core';
727
728 __PACKAGE__-&gt;many_to_many(
729    authors <strong># Accessor name</strong>
730    =&gt; "author_and_books", <strong># has_many</strong>
731    'author' <strong># foreign relationship name</strong>
732 );
733
734 1;</pre>
735    </div>
736
737    <div class="slide">
738       <h1>many_to_many</h1>
739       <pre>package Foo::Schema::Result::Author;
740 use base 'DBIx::Class::Core';
741
742 __PACKAGE__-&gt;many_to_many(
743    "books" <strong># Accessor Name</strong>
744    =&gt; "author_and_books", <strong># has_many accessor_name</strong>
745    'book' <strong># foreign relationship name</strong>
746 );
747
748 1;
749 </pre>
750    </div>
751
752    <div class="slide">
753       <h1>Using many_to_many</h1>
754       <pre>#!perl
755 use Foo::Schema;
756 my $schema    = Foo::Schema-&gt;connect(...);
757 my $author_rs = $schema-&gt;resultset('Authors');
758 my $author    = $author_rs-&gt;search({
759    name =&gt; 'Douglas Adams',
760 })-&gt;single;
761 $author-&gt;add_to_books({
762    title =&gt; 'A new book',
763 });</pre>
764    </div>
765
766    <div class="slide">
767       <h1>using many_to_many</h1>
768       <pre>my $author = $author_rs-&gt;search({
769    name =&gt; 'Douglas Adams',
770 })-&gt;single;
771 <strong>$author-&gt;add_to_books({
772    title =&gt; 'A new book',
773 });</strong>
774
775 # SELECT me.id, me.name FROM authors me
776 #     WHERE ( name = ? ): 'Douglas Adams';
777 # INSERT INTO books (title) VALUES (?): 'A new book';
778 # INSERT INTO author_and_books (author, book)
779 #     VALUES (?, ?): '5', '2';</pre>
780    </div>
781
782    <div class="slide">
783       <h1>using many_to_many</h1>
784       <pre>$author-&gt;add_to_books($book);
785
786 $book-&gt;add_to_authors($author_1);
787 $book-&gt;add_to_authors($author_2);</pre>
788    </div>
789
790    <div class="slide">
791       <h1>errors</h1>
792       <p>Read them closely!</p>
793    </div>
794
795    <div class="slide">
796       <h1>error messages</h1>
797 <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external
798 class definition for 'Foo::Schema::Result::Authors': Can't locate object
799 method "many_to_many" via package "Foo::Schema::Result::Author" at
800 lib/Foo/Schema/Result/Authors.pm line 9.Compilation failed in require at
801 /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre>
802    </div>
803
804    <div class="slide">
805       <h1>error messages</h1>
806 <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external
807 class definition for 'Foo::Schema::Result::Authors': Can't locate object
808 method "many_to_many" via package "Foo::Schema::<strong>Result::Author</strong>" at
809 lib/Foo/Schema/<strong>Result/Authors.pm</strong> line 9.Compilation failed in require at
810 /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre>
811    </div>
812
813    <div class="slide">
814       <h1>errors</h1>
815       <ul>
816          <li>Turn on debugging</li>
817          <li>Read error messages (sometimes useful!)</li>
818          <li>Check field names</li>
819          <li>Check package names</li>
820          <li>Check which database you are connected to (dev/test/live?) - repeat above</li>
821       </ul>
822    </div>
823
824    <div class="slide">
825       <h1>LOTS more Features</h1>
826       <ul>
827          <li>FilterColumn</li>
828          <li>Transactions</li>
829          <li>HashRefInflator</li>
830          <li>Subqueries</li>
831          <li>ResultSetColumn</li>
832          <li>Aggregate Queries</li>
833       </ul>
834    </div>
835
836    <div class="slide">
837       <h1>bonus slides!</h1>
838    </div>
839
840    <div class="slide">
841       <h1>Template Toolkit</h1>
842       <ul>
843          <li><pre>[% author.books.count %]</pre> not working?</li>
844          <li>TT all methods are called in list context</li>
845          <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li>
846          <li><em>Available for all relationships</em></li>
847       </ul>
848    </div>
849
850    <div class="slide">
851       <h1>Catalyst</h1>
852       <pre>package Your::App::Model::<strong>Foo</strong>;
853 use base qw(<strong>Catalyst::Model::Schema::Schema</strong>);
854
855 use strict;
856 use warnings;
857
858 __PACKAGE__-&gt;config(
859   schema_class =&gt; '<strong>Foo::Schema</strong>',
860 );
861
862 1;</pre>
863    <p>Keep your Schema in a <em>separate</em> package from your Catalyst application</p>
864    </div>
865
866    <div class="slide">
867       <h1>Catalyst</h1>
868 <pre>sub action_name : Local {
869   my ($self, $c) = @_;
870
871   my $schema = $c-&gt;model('Schema::Foo');
872   my $author_rs = $schema-&gt;resultset('Authors');
873
874 }
875
876 1;</pre>
877    </div>
878
879 </div>
880 </body>
881 </html>