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