initial commit
[dbsrgits/dbix-class-introduction-presentation.git] / slideshow.html
CommitLineData
52d980cb 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
319my $book = $book_model-&gt;search({
320 title =&gt; 'A book title',
321})-&gt;single;
322
323my @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");
401LPW::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);
415LPW::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");
421LPW::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);
441LPW::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
449LPW::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
458INSERT 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
465LPW::DBIC::ResultSet::Books
466LPW::DBIC::Result::Authors
467LPW::DBIC::ResultSet::Books</pre>
468 </div>
469
470 <div class="slide">
471 <h1>Result::</h1>
472<pre>package LPW::DBIC::Result::Books;
473use base 'DBIx::Class';
474use strict;
475use warnings;
476
477sub 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
4881;</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;
499use base 'DBIx::Class';
500use strict;
501use warnings;
502
503use 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;
517use base 'DBIx::Class';
518use strict;
519use warnings;
520
521use 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;
543print $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;
551use base 'DBIx::Class::ResultSet';
552sub the_ultimate_books {
553 my $self = shift;
554 return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
555}
556sub by_author {
557 my ( $self, $author ) = @_;
558 return $self-&gt;search({ author =&gt; $author-&gt;id })
559}
560
5611;</pre>
562 </div>
563
564 <div class="slide">
565 <h1>ResultSets::</h1>
566<pre>package LPW::DBIC::<strong>ResultSet::Books</strong>;
567use base '<strong>DBIx::Class::ResultSet</strong>';
568sub the_ultimate_books {
569 my $self = shift;
570 <strong>return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } })</strong>
571}
572sub by_author {
573 my ( $self, $author ) = @_;
574 return $self-&gt;search({ author =&gt; $author-&gt;id })
575}
576
5771;</pre>
578 </div>
579
580 <div class="slide">
581 <h1>ResultSets::</h1>
582<pre>package LPW::DBIC::ResultSet::Books;
583use base 'DBIx::Class::ResultSet';
584sub the_ultimate_books {
585 my $self = shift;
586 return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
587}
588sub by_author {
589 my ( $self, $author ) = @_;
590 <strong>return $self-&gt;search({ author =&gt; $author-&gt;id })</strong>
591}
592
5931;</pre>
594 </div>
595
596 <div class="slide">
597 <h1>ResultSets::</h1>
598<pre>use LPW::DBIC;
599my $book_model = LPW::DBIC-&gt;resultset('Books');
600my $book_rs = $book_model-&gt;the_ultimate_books;
601my @books = $book_rs-&gt;all;</pre>
602 </div>
603
604 <div class="slide">
605 <h1>ResultSets::chaining</h1>
606<pre>use LPW::DBIC;
607my $book_model = LPW::DBIC-&gt;resultset('Books');
608my $author_model = LPW::DBIC-&gt;resultset('Authors');
609my $author = $author_model-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
610my $book_rs = $book_model-&gt;the_ultimate_books-&gt;by_author($author);
611my @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>
619or
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
641my @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;
651use base 'DBIx::Class';
652
653sub new {
654 my ( $class, $attrs ) = @_;
655 # Mess with $attrs
656 my $new = $class-&gt;next::method($attrs);
657 return $new
658}
659
6601;</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
690ALTER 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
703ALTER 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(
726author_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>;
765use base 'DBIx::Class';
766
767__PACKAGE__-&gt;many_to_many(
768 authors =&gt; "author_and_books", 'author'
769);
770
7711;
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>;
779use 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
7871;</pre>
788 </div>
789
790 <div class="slide">
791 <h1>many_to_many</h1>
792 <pre>package LPW::DBIC::Result::Authors;
793use 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
8011;
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
810use LPW::DBIC;
811
812my $author_model = LPW::DBIC-&gt;resultset('Authors');
813my $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>;
892use base qw(<strong>Catalyst::Model::DBIC::Schema</strong>);
893
894use strict;
895use warnings;
896
897__PACKAGE__-&gt;config(
898 schema_class =&gt; '<strong>LPW::DBIC</strong>',
899);
900
9011;</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
9151;</pre>
916 </div>
917
918</div>
919</body>
920</html>