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