Commit | Line | Data |
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"> |
7365a110 |
85 | <h1>What's up guys?</h1> |
0cffcad7 |
86 | <div class="notes"> |
87 | <ul> |
88 | <li>How many people have designed a database with Foreign Keys?</li> |
89 | <li>How many people have used any ORM?<ul> |
90 | <li>In Perl?<ul> |
91 | <li>DBIC?</li> |
92 | <li> Class::DBI? </li> |
93 | <li> Rose::DB? </li> |
94 | <li> Fey? </li> |
95 | <li> Others? </li> |
96 | </ul></li> |
97 | <li>AR? </li> |
98 | <li> DataMapper? </li> |
99 | <li>(N)Hibernate?</li> |
100 | </ul></li> |
101 | </ul> |
102 | </div> |
52d980cb |
103 | </div> |
104 | |
105 | <div class="slide"> |
106 | <h1>DBIx::Class?</h1> |
107 | <ul> |
108 | <li>ORM (object relational mapper)</li> |
109 | <li>SQL <-> OO (using objects instead of SQL)</li> |
110 | <li>Simple, powerful, complex, fab and confusing</li> |
111 | <li>There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)</li> |
112 | </ul> |
113 | </div> |
114 | |
115 | <div class="slide"> |
7365a110 |
116 | <h1>Purpose</h1> |
117 | <p>The purpose of this talk is to show you as many features of |
118 | DBIx::Class in 40 minutes |
119 | so that when you need to do something with it later you will |
120 | know what's possible</p> |
52d980cb |
121 | </div> |
122 | |
123 | <div class="slide"> |
7365a110 |
124 | <h1>Basic CRUD</h1> |
52d980cb |
125 | <ul> |
126 | <li><strong>C</strong> - Create</li> |
127 | <li><strong>R</strong> - Read</li> |
128 | <li><strong>U</strong> - Update</li> |
129 | <li><strong>D</strong> - Delete</li> |
130 | </ul> |
131 | </div> |
132 | |
133 | <div class="slide"> |
5cac74c7 |
134 | <h1>SQL: Create</h1> |
52d980cb |
135 | <pre>my $sth = $dbh->prepare(' |
136 | INSERT INTO books |
01b7b88c |
137 | (title, author_id) |
52d980cb |
138 | values (?,?) |
139 | '); |
140 | |
141 | $sth->execute( |
142 | 'A book title', $author_id |
143 | );</pre> |
144 | </div> |
145 | |
146 | <div class="slide"> |
5cac74c7 |
147 | <h1>DBIC: Create</h1> |
01b7b88c |
148 | <pre>my $book = $book_rs->create({ |
149 | title => 'A book title', |
150 | author_id => $author_id, |
52d980cb |
151 | });</pre> |
7365a110 |
152 | <p>Don't need to work to pair placeholders and values</p> |
52d980cb |
153 | </div> |
154 | |
155 | <div class="slide"> |
5cac74c7 |
156 | <h1>DBIC: Create</h1> |
01b7b88c |
157 | <pre>my $pratchett = $author_rs->create({ |
52d980cb |
158 | name => 'Terry Pratchett', |
159 | });</pre> |
160 | </div> |
161 | |
162 | <div class="slide"> |
5cac74c7 |
163 | <h1>DBIC: Create</h1> |
52d980cb |
164 | <pre>my $book = $pratchett->create_related( |
165 | <strong>books</strong> => { |
166 | title => 'Another Discworld book', |
167 | });</pre> |
168 | <strong>or</strong> |
169 | <pre>my $book = $pratchett->add_to_<strong>books</strong>({ |
170 | title => 'Another Discworld book', |
171 | });</pre> |
7365a110 |
172 | <p>Automaticaly fills in foreign key for you</p> |
52d980cb |
173 | </div> |
174 | |
175 | <div class="slide"> |
7365a110 |
176 | <h1>SQL: Read</h1> |
177 | <pre>my $sth = $dbh->prepare(' |
178 | SELECT title, |
179 | authors.name as author_name |
180 | FROM books, authors |
181 | WHERE books.author = authors.id |
182 | ');</pre> |
183 | </div> |
184 | |
185 | <div class="slide"> |
186 | <h1>SQL: Read</h1> |
187 | <pre>while( my $book = $sth->fetchrow_hashref() ) { |
188 | print 'Author of ' |
189 | . $book->{title} |
190 | . ' is ' |
191 | . $book->{author_name} |
192 | . "\n"; |
193 | }</pre> |
52d980cb |
194 | </div> |
195 | |
196 | <div class="slide"> |
5cac74c7 |
197 | <h1>DBIC: Read</h1> |
01b7b88c |
198 | <pre>my $book = $book_rs->find($book_id); |
52d980cb |
199 | |
01b7b88c |
200 | my $book = $book_rs->search({ |
52d980cb |
201 | title => 'A book title', |
5cac74c7 |
202 | }, { rows => 1 })->single; |
52d980cb |
203 | |
01b7b88c |
204 | my @books = $book_rs->search({ |
52d980cb |
205 | author => $author_id, |
206 | })->all;</pre> |
7365a110 |
207 | <p>TMTOWTDI</p> |
52d980cb |
208 | </div> |
209 | |
210 | <div class="slide"> |
5cac74c7 |
211 | <h1>DBIC: Read</h1> |
212 | <pre>while( my $book = $books_rs->next ) { |
52d980cb |
213 | print 'Author of ' |
214 | . $book->title |
215 | . ' is ' |
216 | . $book->author->name |
217 | . "\n"; |
218 | }</pre> |
219 | </div> |
220 | |
221 | <div class="slide"> |
5cac74c7 |
222 | <h1>DBIC: Read</h1> |
01b7b88c |
223 | <pre>my $resultset = $book_rs->search({ |
52d980cb |
224 | author => $author_id, |
225 | });</pre> |
226 | <p>Search takes SQL::Abstract formatted queries</p> |
227 | <pre>> perldoc SQL::Abstract</p> |
228 | </div> |
229 | |
230 | <div class="slide"> |
7365a110 |
231 | <h1>SQL: Update</h1> |
232 | <pre>my $update = $dbh->prepare(' |
233 | UPDATE books |
234 | SET title = ? |
235 | WHERE id = ? |
236 | '); |
237 | |
238 | $update->execute( |
239 | 'New title',<strong>$book_id</strong> |
240 | );</pre> |
241 | </div> |
242 | |
243 | <div class="slide"> |
5cac74c7 |
244 | <h1>DBIC: Update</h1> |
52d980cb |
245 | <pre>$book->update({ |
246 | title => 'New title', |
247 | });</pre> |
248 | </div> |
249 | |
250 | <div class="slide"> |
7365a110 |
251 | <h1>SQL: Delete</h1> |
252 | <pre>my $delete = $dbh->prepare(' |
253 | DELETE FROM books |
254 | WHERE id = ? |
255 | '); |
256 | |
257 | $delete->execute(<strong>$book_id</strong>);</pre> |
258 | </div> |
259 | |
260 | <div class="slide"> |
5cac74c7 |
261 | <h1>DBIC: Delete</h1> |
52d980cb |
262 | <pre>$book->delete;</pre> |
263 | </div> |
264 | |
265 | <div class="slide"> |
266 | <h1>Creating models</h1> |
267 | </div> |
268 | |
269 | <div class="slide"> |
451b57c2 |
270 | <pre>package Foo::Schema::Result::Author; |
492be2ae |
271 | __PACKAGE__->table('authors'); |
272 | __PACKAGE__->add_columns( |
273 | id => { |
01b7b88c |
274 | data_type => 'int', |
275 | is_auto_increment => 1 |
492be2ae |
276 | }, |
277 | title => { |
278 | data_type => 'varchar', |
279 | is_nullable => 1, |
280 | size => 255, |
281 | }, |
282 | ); |
283 | __PACKAGE__->set_primary_key('id'); |
284 | __PACKAGE__->has_many( books => |
451b57c2 |
285 | 'Foo::Schema::Result::Book', 'author_id' |
492be2ae |
286 | ); |
287 | 1; |
288 | </pre> |
289 | </div> |
290 | |
291 | <div class="slide"> |
01b7b88c |
292 | <pre style="float: left; font-size: 80%;">package Foo::Schema::Result::Book; |
492be2ae |
293 | use strict; use warnings; |
294 | __PACKAGE__->table('books'); |
295 | __PACKAGE__->add_columns( |
296 | id => { |
01b7b88c |
297 | data_type => 'int', |
298 | is_auto_increment => 1 |
492be2ae |
299 | }, |
300 | name => { |
301 | data_type => 'varchar', |
302 | is_nullable => 1, |
303 | size => 255, |
304 | }, |
01b7b88c |
305 | </pre> |
306 | <pre style="float: left; font-size: 80%;"> |
492be2ae |
307 | author_id => { |
308 | data_type => 'int', |
309 | size => 8, |
492be2ae |
310 | }, |
311 | ); |
312 | __PACKAGE__->set_primary_key('id'); |
313 | __PACKAGE__->belongs_to( author => |
451b57c2 |
314 | 'Foo::Schema::Result::Author', 'author_id' |
492be2ae |
315 | ); |
316 | 1; |
317 | </pre> |
52d980cb |
318 | </div> |
319 | |
320 | <div class="slide"> |
9158dee5 |
321 | <h1>->deploy</h1> |
322 | <p>Perl -> DB</p> |
323 | <pre>my $schema = Foo::Schema->connect($dsn, $user, $pass); |
324 | $schema->deploy |
325 | </pre> |
326 | <p>See also: <a href="http://search.cpan.org/perldoc?DBIx::Class::DeploymentHandler">DBIx::Class::DeploymentHandler</a></p> |
327 | </div> |
328 | |
329 | <div class="slide"> |
52d980cb |
330 | <h1>Schema::Loader</h1> |
9158dee5 |
331 | <p>DB -> Perl</p> |
451b57c2 |
332 | <pre>package Foo::Schema; |
c7321880 |
333 | use strict; use warnings; |
334 | use base 'DBIx::Class::Schema::Loader'; |
335 | __PACKAGE__->loader_options({ |
336 | naming => 'v7', |
337 | debug => $ENV{DBIC_TRACE}, |
338 | }); |
339 | 1; |
340 | |
341 | # elsewhere... |
342 | |
451b57c2 |
343 | my $schema = Foo::Schema->connect($dsn, $user, $pass); |
c7321880 |
344 | </pre> |
52d980cb |
345 | </div> |
346 | |
347 | <div class="slide"> |
6e5edefe |
348 | <h1>Splitting Logic Cleanly</h1> |
451b57c2 |
349 | <p>Foo::Schema::Result::Bar = individual row</p> |
350 | <p>Foo::Schema::ResultSet::Bar = searches / table </p> |
52d980cb |
351 | </div> |
352 | |
353 | <div class="slide"> |
6e5edefe |
354 | <h1>Using your Schema</h1> |
355 | <pre>#!perl |
356 | use strict; use warnings; |
357 | use lib 'lib'; |
451b57c2 |
358 | use Foo::Schema; |
359 | my $schema = Foo::Schema->connect($dns, $user, $pass); |
6e5edefe |
360 | my $author_rs = $schema->resultset('Author'); |
361 | my $author = $author_rs->create({ |
362 | name => 'Douglas Adams', |
363 | }); |
364 | my $book = $author->add_to_books({ |
365 | title => '42', |
366 | }); |
367 | </pre> |
52d980cb |
368 | </div> |
369 | |
370 | <div class="slide"> |
371 | <h1>DEBUGGING</h1> |
372 | <pre>DBIC_TRACE=1 ./your_script.pl</pre> |
373 | </div> |
374 | |
375 | <div class="slide"> |
52d980cb |
376 | <h1>SQL - debugging</h1> |
377 | <pre>INSERT INTO authors (name) |
378 | VALUES (?): 'Douglas Adams' |
379 | |
380 | INSERT INTO books (author, title) |
381 | VALUES (?, ?): '5', '42'</pre> |
382 | </div> |
383 | |
384 | <div class="slide"> |
385 | <h1>overloading</h1> |
451b57c2 |
386 | <pre>Foo::Schema::Result::Book |
387 | Foo::Schema::ResultSet::Book |
388 | Foo::Schema::Result::Author |
389 | Foo::Schema::ResultSet::Book</pre> |
52d980cb |
390 | </div> |
391 | |
392 | <div class="slide"> |
393 | <h1>Result::</h1> |
2a65778d |
394 | <pre>package Foo::Schema::Result::Book; |
395 | use base 'DBIx::Class::Core'; |
52d980cb |
396 | use strict; |
397 | use warnings; |
398 | |
6e5edefe |
399 | # Result code here |
400 | |
52d980cb |
401 | sub isbn { |
402 | my $self = shift; |
403 | |
404 | # search amazon or something |
405 | my $api = Amazon::API->book({ |
406 | title => $self->title |
407 | }); |
408 | |
409 | return $api->isbn; |
410 | } |
411 | |
412 | 1;</pre> |
413 | </div> |
414 | |
415 | <div class="slide"> |
416 | <h1>Result::</h1> |
417 | <pre>print $book->isbn;</pre> |
418 | </div> |
419 | |
420 | <div class="slide"> |
421 | <h1>Result:: (inflating)</h1> |
2a65778d |
422 | <pre>package Foo::Schema::Result::Book; |
423 | use base 'DBIx::Class::Core'; |
52d980cb |
424 | use strict; |
425 | use warnings; |
426 | |
451b57c2 |
427 | # Result code here |
428 | |
429 | __PACKAGE__->load_components('InflateColumn'); |
52d980cb |
430 | use DateTime::Format::MySQL; |
431 | |
432 | __PACKAGE__-><strong>inflate_column</strong>( |
433 | <strong>date_published</strong> => { |
434 | inflate => sub { DateTime::Format::MySQL->parse_date(shift) }, |
435 | deflate => sub { shift->ymd}, |
451b57c2 |
436 | }, |
52d980cb |
437 | ); |
438 | # Automatic see: DBIx::Class::InflateColumn::DateTime</pre> |
439 | </div> |
440 | |
441 | <div class="slide"> |
52d980cb |
442 | <h1>Result:: (deflating)</h1> |
443 | <pre>$book->date_published(DateTime->now); |
444 | $book->update;</pre> |
445 | </div> |
446 | |
447 | <div class="slide"> |
448 | <h1>Result:: (inflating)</h1> |
449 | <pre>my $date_published = $book->date_published; |
450 | print $date_published->month_abbr;</pre> |
451 | |
452 | <strong><em>Nov</em></strong> |
453 | </div> |
454 | |
455 | <div class="slide"> |
456 | <h1>ResultSets::</h1> |
41a0eb8e |
457 | <pre>package Foo::Schema::ResultSet::Books; |
52d980cb |
458 | use base 'DBIx::Class::ResultSet'; |
459 | sub the_ultimate_books { |
460 | my $self = shift; |
461 | return $self->search({ title => { -like => '%42%' } }); |
462 | } |
463 | sub by_author { |
464 | my ( $self, $author ) = @_; |
465 | return $self->search({ author => $author->id }) |
466 | } |
467 | |
468 | 1;</pre> |
469 | </div> |
470 | |
471 | <div class="slide"> |
472 | <h1>ResultSets::</h1> |
41a0eb8e |
473 | <pre>use Foo::Schema; |
451b57c2 |
474 | my $schema = Foo::Schema->connect(...); |
475 | my $book_rs = Foo::Schema->resultset('Book'); |
476 | my $book_search = $book_rs->the_ultimate_books; |
477 | my @books = $book_search->all;</pre> |
52d980cb |
478 | </div> |
479 | |
480 | <div class="slide"> |
451b57c2 |
481 | <h1>ResultSets: Chaining</h1> |
482 | <pre> |
01b7b88c |
483 | my $book_rs = $schema->resultset('Book'); |
484 | my $author_rs = $schema->resultset('Author'); |
485 | my $author = $author_rs->search({ name => 'Douglas Adams' })->single; |
486 | $book_rs = $book_rs->the_ultimate_books->by_author($author); |
487 | my @books = $book_rs->all;</pre> |
52d980cb |
488 | </div> |
489 | |
490 | <div class="slide"> |
451b57c2 |
491 | <h1>ResultSets: Chaining</h1> |
492 | <pre>$book_rs = $schema->resultset('Book') |
52d980cb |
493 | ->the_ultimate_books |
494 | ->by_author($author);</pre> |
495 | or |
496 | |
451b57c2 |
497 | <pre>my $book_rs = $schema->resultset('Book') |
2a65778d |
498 | ->the_ultimate_books; |
52d980cb |
499 | $book_rs = $book_rs->by_author($author);</pre> |
500 | <pre># Debug (SQL): |
501 | |
502 | # SELECT me.id, me.title, me.date_published, me.author |
503 | # FROM books me |
504 | # WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%' |
505 | # WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre> |
506 | </div> |
507 | |
508 | <div class="slide"> |
01b7b88c |
509 | <h1>ResultSets: Chaining</h1> |
510 | <pre>my $rs = $book_rs |
52d980cb |
511 | ->category('childrens') |
512 | ->by_author($author) |
513 | ->published_after('1812') |
514 | ->first_page_contains('once upon') |
515 | ->rating_greater_than(4); |
516 | |
517 | my @books = $rs->all;</pre> |
518 | </div> |
519 | |
520 | <div class="slide"> |
521 | <h1>overloading before new record</h1> |
2a65778d |
522 | <pre>package Foo::Schema::Result::Author; |
523 | use base 'DBIx::Class::Core'; |
52d980cb |
524 | |
525 | sub new { |
526 | my ( $class, $attrs ) = @_; |
527 | # Mess with $attrs |
528 | my $new = $class->next::method($attrs); |
529 | return $new |
530 | } |
531 | |
532 | 1;</pre> |
533 | |
534 | <div class="slide"> |
6548782a |
535 | <h1>Relationships</h1> |
52d980cb |
536 | </div> |
537 | |
538 | <div class="slide"> |
6548782a |
539 | <h1>Multiple Authors</h1> |
01b7b88c |
540 | <p>We want to allow a book to be by more than one author</p> |
52d980cb |
541 | </div> |
542 | |
543 | <div class="slide"> |
544 | <h1>a few relationships</h1> |
9158dee5 |
545 | <img src="img/afewrels.png" /> |
52d980cb |
546 | </div> |
547 | |
548 | <div class="slide"> |
6548782a |
549 | <h1>Join Table</h1> |
52d980cb |
550 | <pre>CREATE TABLE author_and_books( |
6548782a |
551 | book_id int(8), |
552 | author_id int(8), |
553 | foreign key (book_id) references books(id), |
554 | foreign key (author_id) references authors(id) |
52d980cb |
555 | ) engine = InnoDB DEFAULT CHARSET=utf8; |
556 | |
01b7b88c |
557 | ALTER TABLE `books` DROP `author_id`;</pre> |
52d980cb |
558 | </div> |
559 | |
560 | <div class="slide"> |
561 | <h1>has_many</h1> |
9158dee5 |
562 | <img src="img/hasmany1.png" /> |
52d980cb |
563 | </div> |
564 | |
565 | <div class="slide"> |
566 | <h1>has_many</h1> |
6548782a |
567 | <pre>package Foo::Schema::<strong>Result::Book</strong>; |
52d980cb |
568 | |
6548782a |
569 | __PACKAGE__->has_many( author_and_books => |
570 | 'Foo::Schema::Result::Author_Book', 'book_id' |
52d980cb |
571 | ); |
52d980cb |
572 | </div> |
573 | |
574 | <div class="slide"> |
575 | <h1>belongs_to</h1> |
9158dee5 |
576 | <img src="img/belongsto1.png" /> |
52d980cb |
577 | </div> |
578 | |
579 | <div class="slide"> |
580 | <h1>belongs_to</h1> |
6548782a |
581 | <pre>package Foo::Schema::<strong>Result::Author_Book</strong>; |
52d980cb |
582 | |
583 | __PACKAGE__->belongs_to( |
6548782a |
584 | book => |
585 | 'Foo::Schema::Result::Book', 'book_id' |
52d980cb |
586 | ); |
587 | </pre> |
588 | </div> |
589 | |
590 | <div class="slide"> |
591 | <h1>same for Authors</h1> |
9158dee5 |
592 | <img src="img/authors.png" /> |
52d980cb |
593 | </div> |
594 | |
595 | <div class="slide"> |
52d980cb |
596 | <h1>many_to_many</h1> |
9158dee5 |
597 | <img src="img/m2m.png" /> |
52d980cb |
598 | </div> |
599 | |
600 | <div class="slide"> |
601 | <h1>many_to_many</h1> |
2a65778d |
602 | <pre>package Foo::Schema::<strong>Result::Book</strong>; |
603 | use base 'DBIx::Class::Core'; |
52d980cb |
604 | |
605 | __PACKAGE__->many_to_many( |
6548782a |
606 | authors => 'author_and_books', 'author' |
52d980cb |
607 | ); |
608 | |
609 | 1; |
6548782a |
610 | </pre> |
52d980cb |
611 | </div> |
612 | |
613 | <div class="slide"> |
614 | <h1>many_to_many</h1> |
2a65778d |
615 | <pre>package Foo::Schema::<strong>Result::Book</strong>; |
616 | use base 'DBIx::Class::Core'; |
52d980cb |
617 | |
618 | __PACKAGE__->many_to_many( |
619 | authors <strong># Accessor name</strong> |
620 | => "author_and_books", <strong># has_many</strong> |
621 | 'author' <strong># foreign relationship name</strong> |
622 | ); |
623 | |
624 | 1;</pre> |
625 | </div> |
626 | |
627 | <div class="slide"> |
628 | <h1>many_to_many</h1> |
2a65778d |
629 | <pre>package Foo::Schema::Result::Author; |
630 | use base 'DBIx::Class::Core'; |
52d980cb |
631 | |
632 | __PACKAGE__->many_to_many( |
633 | "books" <strong># Accessor Name</strong> |
634 | => "author_and_books", <strong># has_many accessor_name</strong> |
635 | 'book' <strong># foreign relationship name</strong> |
636 | ); |
637 | |
638 | 1; |
6548782a |
639 | </pre> |
52d980cb |
640 | </div> |
641 | |
642 | <div class="slide"> |
6c562ff1 |
643 | <h1>Using many_to_many</h1> |
644 | <pre>#!perl |
41a0eb8e |
645 | use Foo::Schema; |
6c562ff1 |
646 | my $schema = Foo::Schema->connect(...); |
647 | my $author_rs = $schema->resultset('Authors'); |
01b7b88c |
648 | my $author = $author_rs->search({ |
52d980cb |
649 | name => 'Douglas Adams', |
650 | })->single; |
651 | $author->add_to_books({ |
652 | title => 'A new book', |
653 | });</pre> |
654 | </div> |
655 | |
656 | <div class="slide"> |
657 | <h1>using many_to_many</h1> |
01b7b88c |
658 | <pre>my $author = $author_rs->search({ |
52d980cb |
659 | name => 'Douglas Adams', |
660 | })->single; |
661 | <strong>$author->add_to_books({ |
662 | title => 'A new book', |
663 | });</strong> |
664 | |
665 | # SELECT me.id, me.name FROM authors me |
666 | # WHERE ( name = ? ): 'Douglas Adams'; |
667 | # INSERT INTO books (title) VALUES (?): 'A new book'; |
668 | # INSERT INTO author_and_books (author, book) |
669 | # VALUES (?, ?): '5', '2';</pre> |
670 | </div> |
671 | |
672 | <div class="slide"> |
673 | <h1>using many_to_many</h1> |
674 | <pre>$author->add_to_books($book); |
675 | |
676 | $book->add_to_authors($author_1); |
677 | $book->add_to_authors($author_2);</pre> |
678 | </div> |
679 | |
680 | <div class="slide"> |
52d980cb |
681 | <h1>errors</h1> |
682 | <p>Read them closely!</p> |
683 | </div> |
684 | |
685 | <div class="slide"> |
686 | <h1>error messages</h1> |
01b7b88c |
687 | <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external |
688 | class definition for 'Foo::Schema::Result::Authors': Can't locate object |
689 | method "many_to_many" via package "Foo::Schema::Result::Author" at |
690 | lib/Foo/Schema/Result/Authors.pm line 9.Compilation failed in require at |
691 | /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre> |
52d980cb |
692 | </div> |
693 | |
694 | <div class="slide"> |
695 | <h1>error messages</h1> |
01b7b88c |
696 | <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external |
697 | class definition for 'Foo::Schema::Result::Authors': Can't locate object |
698 | method "many_to_many" via package "Foo::Schema::<strong>Result::Author</strong>" at |
699 | lib/Foo/Schema/<strong>Result/Authors.pm</strong> line 9.Compilation failed in require at |
700 | /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre> |
52d980cb |
701 | </div> |
702 | |
703 | <div class="slide"> |
704 | <h1>errors</h1> |
705 | <ul> |
706 | <li>Turn on debugging</li> |
707 | <li>Read error messages (sometimes useful!)</li> |
708 | <li>Check field names</li> |
709 | <li>Check package names</li> |
710 | <li>Check which database you are connected to (dev/test/live?) - repeat above</li> |
711 | </ul> |
712 | </div> |
713 | |
714 | <div class="slide"> |
9158dee5 |
715 | <h1>LOTS more Features</h1> |
716 | <ul> |
717 | <li>FilterColumn</li> |
718 | <li>Transactions</li> |
719 | <li>HashRefInflator</li> |
720 | <li>Subqueries</li> |
721 | <li>ResultSetColumn</li> |
01b7b88c |
722 | <li>Aggregate Queries</li> |
9158dee5 |
723 | </ul> |
724 | </div> |
725 | |
726 | <div class="slide"> |
52d980cb |
727 | <h1>bonus slides!</h1> |
728 | </div> |
729 | |
730 | <div class="slide"> |
731 | <h1>Template Toolkit</h1> |
732 | <ul> |
733 | <li><pre>[% author.books.count %]</pre> not working?</li> |
734 | <li>TT all methods are called in list context</li> |
735 | <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li> |
736 | <li><em>Available for all relationships</em></li> |
737 | </ul> |
738 | </div> |
739 | |
740 | <div class="slide"> |
741 | <h1>Catalyst</h1> |
0cffcad7 |
742 | <pre>package Your::App::Model::<strong>Foo</strong>; |
41a0eb8e |
743 | use base qw(<strong>Catalyst::Model::Schema::Schema</strong>); |
52d980cb |
744 | |
745 | use strict; |
746 | use warnings; |
747 | |
748 | __PACKAGE__->config( |
41a0eb8e |
749 | schema_class => '<strong>Foo::Schema</strong>', |
52d980cb |
750 | ); |
751 | |
752 | 1;</pre> |
01b7b88c |
753 | <p>Keep your Schema in a <em>separate</em> package from your Catalyst application</p> |
52d980cb |
754 | </div> |
755 | |
756 | <div class="slide"> |
757 | <h1>Catalyst</h1> |
758 | <pre>sub action_name : Local { |
759 | my ($self, $c) = @_; |
760 | |
01b7b88c |
761 | my $schema = $c->model('Schema::Foo'); |
762 | my $author_rs = $schema->resultset('Authors'); |
52d980cb |
763 | |
764 | } |
765 | |
766 | 1;</pre> |
767 | </div> |
768 | |
769 | </div> |
770 | </body> |
771 | </html> |