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