Updated cookbook example
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Manual / Cookbook.pod
CommitLineData
3b44ccc6 1=head1 NAME
9c82c181 2
40dbc108 3DBIx::Class::Manual::Cookbook - Miscellaneous recipes
ee38fa40 4
40dbc108 5=head1 RECIPES
2913b2d3 6
bade79c4 7=head2 Searching
faf62551 8
bade79c4 9=head3 Paged results
faf62551 10
bade79c4 11When you expect a large number of results, you can ask L<DBIx::Class> for a
12paged resultset, which will fetch only a small number of records at a time:
faf62551 13
bade79c4 14 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 15 undef,
bade79c4 16 {
17 page => 1, # page to return (defaults to 1)
18 rows => 10, # number of results per page
19 },
20 );
faf62551 21
bade79c4 22 return $rs->all(); # all records for page 1
faf62551 23
bade79c4 24The C<page> attribute does not have to be specified in your search:
25
26 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 27 undef,
bade79c4 28 {
29 rows => 10,
30 }
31 );
faf62551 32
bade79c4 33 return $rs->page(1); # DBIx::Class::ResultSet containing first 10 records
faf62551 34
35In either of the above cases, you can return a L<Data::Page> object for the
bade79c4 36resultset (suitable for use in e.g. a template) using the C<pager> method:
faf62551 37
bade79c4 38 return $rs->pager();
faf62551 39
bade79c4 40=head3 Complex WHERE clauses
2913b2d3 41
40dbc108 42Sometimes you need to formulate a query using specific operators:
43
ea6309e2 44 my @albums = $schema->resultset('Album')->search({
35d4fe78 45 artist => { 'like', '%Lamb%' },
46 title => { 'like', '%Fear of Fours%' },
47 });
40dbc108 48
49This results in something like the following C<WHERE> clause:
50
35d4fe78 51 WHERE artist LIKE '%Lamb%' AND title LIKE '%Fear of Fours%'
40dbc108 52
53Other queries might require slightly more complex logic:
54
ea6309e2 55 my @albums = $schema->resultset('Album')->search({
35d4fe78 56 -or => [
57 -and => [
58 artist => { 'like', '%Smashing Pumpkins%' },
59 title => 'Siamese Dream',
60 ],
61 artist => 'Starchildren',
62 ],
63 });
40dbc108 64
65This results in the following C<WHERE> clause:
66
35d4fe78 67 WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' )
68 OR artist = 'Starchildren'
40dbc108 69
70For more information on generating complex queries, see
71L<SQL::Abstract/WHERE CLAUSES>.
ee38fa40 72
bade79c4 73=head3 Using specific columns
faf62551 74
324572ca 75When you only want specific columns from a table, you can use
76C<columns> to specify which ones you need. This is useful to avoid
77loading columns with large amounts of data that you aren't about to
78use anyway:
faf62551 79
bade79c4 80 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 81 undef,
bade79c4 82 {
5e8b1b2a 83 columns => [qw/ name /]
bade79c4 84 }
85 );
faf62551 86
bade79c4 87 # Equivalent SQL:
88 # SELECT artist.name FROM artist
faf62551 89
324572ca 90This is a shortcut for C<select> and C<as>, see below. C<columns>
91cannot be used together with C<select> and C<as>.
92
bade79c4 93=head3 Using database functions or stored procedures
faf62551 94
bade79c4 95The combination of C<select> and C<as> can be used to return the result of a
96database function or stored procedure as a column value. You use C<select> to
97specify the source for your column value (e.g. a column name, function, or
98stored procedure name). You then use C<as> to set the column name you will use
99to access the returned value:
faf62551 100
bade79c4 101 my $rs = $schema->resultset('Artist')->search(
324572ca 102 {},
bade79c4 103 {
104 select => [ 'name', { LENGTH => 'name' } ],
105 as => [qw/ name name_length /],
106 }
107 );
faf62551 108
bade79c4 109 # Equivalent SQL:
98b65433 110 # SELECT name name, LENGTH( name )
bade79c4 111 # FROM artist
faf62551 112
d676881f 113Note that the C< as > attribute has absolutely nothing to with the sql
114syntax C< SELECT foo AS bar > (see the documentation in
115L<DBIx::Class::ResultSet/ATTRIBUTES>). If your alias exists as a
116column in your base class (i.e. it was added with C<add_columns>), you
117just access it as normal. Our C<Artist> class has a C<name> column, so
118we just use the C<name> accessor:
faf62551 119
bade79c4 120 my $artist = $rs->first();
121 my $name = $artist->name();
faf62551 122
123If on the other hand the alias does not correspond to an existing column, you
324572ca 124have to fetch the value using the C<get_column> accessor:
faf62551 125
bade79c4 126 my $name_length = $artist->get_column('name_length');
faf62551 127
bade79c4 128If you don't like using C<get_column>, you can always create an accessor for
faf62551 129any of your aliases using either of these:
130
bade79c4 131 # Define accessor manually:
132 sub name_length { shift->get_column('name_length'); }
faf62551 133
bade79c4 134 # Or use DBIx::Class::AccessorGroup:
135 __PACKAGE__->mk_group_accessors('column' => 'name_length');
faf62551 136
bade79c4 137=head3 SELECT DISTINCT with multiple columns
faf62551 138
bade79c4 139 my $rs = $schema->resultset('Foo')->search(
324572ca 140 {},
bade79c4 141 {
142 select => [
143 { distinct => [ $source->columns ] }
144 ],
d676881f 145 as => [ $source->columns ] # remember 'as' is not the same as SQL AS :-)
bade79c4 146 }
147 );
faf62551 148
286f32b3 149 my $count = $rs->next->get_column('count');
150
bade79c4 151=head3 SELECT COUNT(DISTINCT colname)
6607ee1b 152
bade79c4 153 my $rs = $schema->resultset('Foo')->search(
324572ca 154 {},
bade79c4 155 {
156 select => [
157 { count => { distinct => 'colname' } }
158 ],
159 as => [ 'count' ]
160 }
161 );
6607ee1b 162
bade79c4 163=head3 Grouping results
164
165L<DBIx::Class> supports C<GROUP BY> as follows:
166
167 my $rs = $schema->resultset('Artist')->search(
324572ca 168 {},
bade79c4 169 {
170 join => [qw/ cds /],
171 select => [ 'name', { count => 'cds.cdid' } ],
172 as => [qw/ name cd_count /],
173 group_by => [qw/ name /]
174 }
175 );
6607ee1b 176
bade79c4 177 # Equivalent SQL:
178 # SELECT name, COUNT( cds.cdid ) FROM artist me
179 # LEFT JOIN cd cds ON ( cds.artist = me.artistid )
180 # GROUP BY name
6607ee1b 181
d676881f 182Please see L<DBIx::Class::ResultSet/ATTRIBUTES> documentation if you
183are in any way unsure about the use of the attributes above (C< join
184>, C< select >, C< as > and C< group_by >).
185
74dc2edc 186=head3 Predefined searches
187
324572ca 188You can write your own L<DBIx::Class::ResultSet> class by inheriting from it
74dc2edc 189and define often used searches as methods:
190
191 package My::DBIC::ResultSet::CD;
192 use strict;
193 use warnings;
194 use base 'DBIx::Class::ResultSet';
195
196 sub search_cds_ordered {
197 my ($self) = @_;
198
199 return $self->search(
200 {},
201 { order_by => 'name DESC' },
202 );
203 }
204
205 1;
206
207To use your resultset, first tell DBIx::Class to create an instance of it
208for you, in your My::DBIC::Schema::CD class:
209
210 __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
211
212Then call your new method in your code:
213
214 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
215
216
d6ed6a67 217=head3 Predefined searches without writing a ResultSet class
218
219Alternatively you can automatically generate a DBIx::Class::ResultSet
220class by using the ResultSetManager component and tagging your method
221as ResultSet:
222
223 __PACKAGE__->load_components(qw/ ResultSetManager Core /);
224
225 sub search_cds_ordered : ResultSet {
226 my ($self) = @_;
227 return $self->search(
228 {},
229 { order_by => 'name DESC' },
230 );
231 }
232
233Then call your method in the same way from your code:
234
235 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
236
87980de7 237=head2 Using joins and prefetch
238
bade79c4 239You can use the C<join> attribute to allow searching on, or sorting your
240results by, one or more columns in a related table. To return all CDs matching
241a particular artist name:
ea6309e2 242
bade79c4 243 my $rs = $schema->resultset('CD')->search(
244 {
245 'artist.name' => 'Bob Marley'
246 },
247 {
248 join => [qw/artist/], # join the artist table
249 }
250 );
251
252 # Equivalent SQL:
253 # SELECT cd.* FROM cd
254 # JOIN artist ON cd.artist = artist.id
255 # WHERE artist.name = 'Bob Marley'
256
257If required, you can now sort on any column in the related tables by including
258it in your C<order_by> attribute:
259
260 my $rs = $schema->resultset('CD')->search(
261 {
262 'artist.name' => 'Bob Marley'
263 },
264 {
265 join => [qw/ artist /],
266 order_by => [qw/ artist.name /]
267 }
268 };
ea6309e2 269
bade79c4 270 # Equivalent SQL:
271 # SELECT cd.* FROM cd
272 # JOIN artist ON cd.artist = artist.id
273 # WHERE artist.name = 'Bob Marley'
274 # ORDER BY artist.name
ea6309e2 275
bade79c4 276Note that the C<join> attribute should only be used when you need to search or
277sort using columns in a related table. Joining related tables when you only
278need columns from the main table will make performance worse!
ea6309e2 279
bade79c4 280Now let's say you want to display a list of CDs, each with the name of the
281artist. The following will work fine:
ea6309e2 282
bade79c4 283 while (my $cd = $rs->next) {
284 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
285 }
ea6309e2 286
bade79c4 287There is a problem however. We have searched both the C<cd> and C<artist> tables
288in our main query, but we have only returned data from the C<cd> table. To get
289the artist name for any of the CD objects returned, L<DBIx::Class> will go back
290to the database:
ea6309e2 291
bade79c4 292 SELECT artist.* FROM artist WHERE artist.id = ?
ea6309e2 293
294A statement like the one above will run for each and every CD returned by our
295main query. Five CDs, five extra queries. A hundred CDs, one hundred extra
296queries!
297
bade79c4 298Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem.
897342e4 299This allows you to fetch results from related tables in advance:
ea6309e2 300
bade79c4 301 my $rs = $schema->resultset('CD')->search(
302 {
303 'artist.name' => 'Bob Marley'
304 },
305 {
306 join => [qw/ artist /],
307 order_by => [qw/ artist.name /],
308 prefetch => [qw/ artist /] # return artist data too!
309 }
310 );
ea6309e2 311
bade79c4 312 # Equivalent SQL (note SELECT from both "cd" and "artist"):
313 # SELECT cd.*, artist.* FROM cd
314 # JOIN artist ON cd.artist = artist.id
315 # WHERE artist.name = 'Bob Marley'
316 # ORDER BY artist.name
ea6309e2 317
318The code to print the CD list remains the same:
319
bade79c4 320 while (my $cd = $rs->next) {
321 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
322 }
ea6309e2 323
bade79c4 324L<DBIx::Class> has now prefetched all matching data from the C<artist> table,
ea6309e2 325so no additional SQL statements are executed. You now have a much more
326efficient query.
327
77d6b403 328Note that as of L<DBIx::Class> 0.05999_01, C<prefetch> I<can> be used with
329C<has_many> relationships.
ea6309e2 330
bade79c4 331Also note that C<prefetch> should only be used when you know you will
ea6309e2 332definitely use data from a related table. Pre-fetching related tables when you
333only need columns from the main table will make performance worse!
334
bade79c4 335=head3 Multi-step joins
ea6309e2 336
337Sometimes you want to join more than one relationship deep. In this example,
bade79c4 338we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes>
339contain a specific string:
340
341 # Relationships defined elsewhere:
342 # Artist->has_many('cds' => 'CD', 'artist');
343 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
344
345 my $rs = $schema->resultset('Artist')->search(
346 {
347 'liner_notes.notes' => { 'like', '%some text%' },
348 },
349 {
350 join => {
351 'cds' => 'liner_notes'
352 }
353 }
354 );
ea6309e2 355
bade79c4 356 # Equivalent SQL:
357 # SELECT artist.* FROM artist
358 # JOIN ( cd ON artist.id = cd.artist )
359 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
360 # WHERE liner_notes.notes LIKE '%some text%'
ea6309e2 361
362Joins can be nested to an arbitrary level. So if we decide later that we
363want to reduce the number of Artists returned based on who wrote the liner
364notes:
365
bade79c4 366 # Relationship defined elsewhere:
367 # LinerNotes->belongs_to('author' => 'Person');
368
369 my $rs = $schema->resultset('Artist')->search(
370 {
371 'liner_notes.notes' => { 'like', '%some text%' },
372 'author.name' => 'A. Writer'
373 },
374 {
375 join => {
376 'cds' => {
377 'liner_notes' => 'author'
ea6309e2 378 }
bade79c4 379 }
380 }
381 );
ea6309e2 382
bade79c4 383 # Equivalent SQL:
384 # SELECT artist.* FROM artist
385 # JOIN ( cd ON artist.id = cd.artist )
386 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
387 # JOIN ( author ON author.id = liner_notes.author )
388 # WHERE liner_notes.notes LIKE '%some text%'
389 # AND author.name = 'A. Writer'
87980de7 390
897342e4 391=head2 Multi-step prefetch
392
393From 0.04999_05 onwards, C<prefetch> can be nested more than one relationship
394deep using the same syntax as a multi-step join:
395
396 my $rs = $schema->resultset('Tag')->search(
ac2803ef 397 {},
897342e4 398 {
399 prefetch => {
400 cd => 'artist'
401 }
402 }
403 );
404
405 # Equivalent SQL:
406 # SELECT tag.*, cd.*, artist.* FROM tag
407 # JOIN cd ON tag.cd = cd.cdid
408 # JOIN artist ON cd.artist = artist.artistid
409
410Now accessing our C<cd> and C<artist> relationships does not need additional
411SQL statements:
412
413 my $tag = $rs->first;
414 print $tag->cd->artist->name;
415
ac2803ef 416=head2 Columns of data
417
418If you want to find the sum of a particular column there are several
419ways, the obvious one is to use search:
420
421 my $rs = $schema->resultset('Items')->search(
422 {},
423 {
424 select => [ { sum => 'Cost' } ],
d676881f 425 as => [ 'total_cost' ], # remember this 'as' is for DBIx::Class::ResultSet not SQL
ac2803ef 426 }
427 );
428 my $tc = $rs->first->get_column('total_cost');
429
430Or, you can use the L<DBIx::Class::ResultSetColumn>, which gets
431returned when you ask the C<ResultSet> for a column using
432C<get_column>:
433
434 my $cost = $schema->resultset('Items')->get_column('Cost');
435 my $tc = $cost->sum;
436
437With this you can also do:
438
439 my $minvalue = $cost->min;
440 my $maxvalue = $cost->max;
441
442Or just iterate through the values of this column only:
443
444 while ( my $c = $cost->next ) {
445 print $c;
446 }
447
448 foreach my $c ($cost->all) {
449 print $c;
450 }
451
709353af 452C<ResultSetColumn> only has a limited number of built-in functions, if
453you need one that it doesn't have, then you can use the C<func> method
454instead:
455
456 my $avg = $cost->func('AVERAGE');
457
458This will cause the following SQL statement to be run:
459
460 SELECT AVERAGE(Cost) FROM Items me
461
462Which will of course only work if your database supports this function.
ac2803ef 463See L<DBIx::Class::ResultSetColumn> for more documentation.
464
acee4e4d 465=head2 Using relationships
466
467=head3 Create a new row in a related table
468
469 my $book->create_related('author', { name => 'Fred'});
470
471=head3 Search in a related table
472
473Only searches for books named 'Titanic' by the author in $author.
474
475 my $author->search_related('books', { name => 'Titanic' });
476
477=head3 Delete data in a related table
478
479Deletes only the book named Titanic by the author in $author.
480
481 my $author->delete_related('books', { name => 'Titanic' });
482
f8bad769 483=head3 Ordering a relationship result set
484
485If you always want a relation to be ordered, you can specify this when you
486create the relationship.
487
488To order C<< $book->pages >> by descending page_number.
489
490 Book->has_many('pages' => 'Page', 'book', { order_by => \'page_number DESC'} );
491
492
493
87980de7 494=head2 Transactions
495
496As of version 0.04001, there is improved transaction support in
181a28f4 497L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>. Here is an
498example of the recommended way to use it:
87980de7 499
181a28f4 500 my $genus = $schema->resultset('Genus')->find(12);
501
70634260 502 my $coderef2 = sub {
503 $genus->extinct(1);
504 $genus->update;
505 };
506
181a28f4 507 my $coderef1 = sub {
35d4fe78 508 $genus->add_to_species({ name => 'troglodyte' });
509 $genus->wings(2);
510 $genus->update;
70634260 511 $schema->txn_do($coderef2); # Can have a nested transaction
181a28f4 512 return $genus->species;
513 };
514
181a28f4 515 my $rs;
516 eval {
70634260 517 $rs = $schema->txn_do($coderef1);
181a28f4 518 };
519
520 if ($@) { # Transaction failed
521 die "the sky is falling!" #
522 if ($@ =~ /Rollback failed/); # Rollback failed
523
524 deal_with_failed_transaction();
35d4fe78 525 }
87980de7 526
181a28f4 527Nested transactions will work as expected. That is, only the outermost
528transaction will actually issue a commit to the $dbh, and a rollback
529at any level of any transaction will cause the entire nested
530transaction to fail. Support for savepoints and for true nested
40dbc108 531transactions (for databases that support them) will hopefully be added
532in the future.
ee38fa40 533
130c6439 534=head2 Many-to-many relationships
ee38fa40 535
787d6a29 536This is straightforward using L<ManyToMany|DBIx::Class::Relationship/many_to_many>:
ea6309e2 537
bade79c4 538 package My::DB;
539 # ... set up connection ...
540
541 package My::User;
542 use base 'My::DB';
543 __PACKAGE__->table('user');
544 __PACKAGE__->add_columns(qw/id name/);
545 __PACKAGE__->set_primary_key('id');
546 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
547 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
548
549 package My::UserAddress;
550 use base 'My::DB';
551 __PACKAGE__->table('user_address');
552 __PACKAGE__->add_columns(qw/user address/);
553 __PACKAGE__->set_primary_key(qw/user address/);
554 __PACKAGE__->belongs_to('user' => 'My::User');
555 __PACKAGE__->belongs_to('address' => 'My::Address');
556
557 package My::Address;
558 use base 'My::DB';
559 __PACKAGE__->table('address');
560 __PACKAGE__->add_columns(qw/id street town area_code country/);
561 __PACKAGE__->set_primary_key('id');
562 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
563 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
564
565 $rs = $user->addresses(); # get all addresses for a user
566 $rs = $address->users(); # get all users for an address
567
568=head2 Setting default values for a row
a00e1684 569
35d4fe78 570It's as simple as overriding the C<new> method. Note the use of
40dbc108 571C<next::method>.
a00e1684 572
35d4fe78 573 sub new {
8b50216e 574 my ( $self, $attrs ) = @_;
40dbc108 575
35d4fe78 576 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
40dbc108 577
8b50216e 578 $self->next::method($attrs);
579
580 return $self;
35d4fe78 581 }
a00e1684 582
4a3c6354 583For more information about C<next::method>, look in the L<Class::C3>
584documentation. See also L<DBIx::Class::Manual::Component> for more
585ways to write your own base classes to do this.
586
587People looking for ways to do "triggers" with DBIx::Class are probably
588just looking for this.
589
25af00d7 590=head2 Stringification
591
40dbc108 592Employ the standard stringification technique by using the C<overload>
462bb847 593module.
594
595To make an object stringify itself as a single column, use something
596like this (replace C<foo> with the column/method of your choice):
25af00d7 597
0472cc04 598 use overload '""' => sub { shift->name}, fallback => 1;
25af00d7 599
462bb847 600For more complex stringification, you can use an anonymous subroutine:
601
602 use overload '""' => sub { $_[0]->name . ", " .
603 $_[0]->address }, fallback => 1;
604
324572ca 605=head3 Stringification Example
462bb847 606
607Suppose we have two tables: C<Product> and C<Category>. The table
608specifications are:
609
610 Product(id, Description, category)
611 Category(id, Description)
612
613C<category> is a foreign key into the Category table.
614
615If you have a Product object C<$obj> and write something like
616
617 print $obj->category
618
619things will not work as expected.
620
621To obtain, for example, the category description, you should add this
622method to the class defining the Category table:
623
624 use overload "" => sub {
625 my $self = shift;
626
627 return $self->Description;
77713550 628 }, fallback => 1;
462bb847 629
bade79c4 630=head2 Disconnecting cleanly
631
632If you find yourself quitting an app with Control-C a lot during
633development, you might like to put the following signal handler in
634your main database class to make sure it disconnects cleanly:
635
636 $SIG{INT} = sub {
6d1bf0a9 637 __PACKAGE__->storage->disconnect;
bade79c4 638 };
639
362500af 640=head2 Schema import/export
641
642This functionality requires you to have L<SQL::Translator> (also known as
643"SQL Fairy") installed.
644
645To create a DBIx::Class schema from an existing database:
646
647 sqlt --from DBI
648 --to DBIx::Class::File
649 --prefix "MySchema" > MySchema.pm
650
651To create a MySQL database from an existing L<DBIx::Class> schema, convert the
652schema to MySQL's dialect of SQL:
653
54c30987 654 sqlt --from SQL::Translator::Parser::DBIx::Class
655 --to MySQL
656 --DBIx::Class "MySchema.pm" > Schema1.sql
362500af 657
658And import using the mysql client:
659
660 mysql -h "host" -D "database" -u "user" -p < Schema1.sql
661
b0a20454 662=head2 Easy migration from class-based to schema-based setup
663
664You want to start using the schema-based approach to L<DBIx::Class>
665(see L<SchemaIntro.pod>), but have an established class-based setup with lots
666of existing classes that you don't want to move by hand. Try this nifty script
667instead:
668
669 use MyDB;
670 use SQL::Translator;
671
672 my $schema = MyDB->schema_instance;
673
674 my $translator = SQL::Translator->new(
675 debug => $debug || 0,
676 trace => $trace || 0,
677 no_comments => $no_comments || 0,
678 show_warnings => $show_warnings || 0,
679 add_drop_table => $add_drop_table || 0,
680 validate => $validate || 0,
681 parser_args => {
682 'DBIx::Schema' => $schema,
c5f36986 683 },
b0a20454 684 producer_args => {
685 'prefix' => 'My::Schema',
c5f36986 686 },
b0a20454 687 );
688
d240abac 689 $translator->parser('SQL::Translator::Parser::DBIx::Class');
690 $translator->producer('SQL::Translator::Producer::DBIx::Class::File');
b0a20454 691
692 my $output = $translator->translate(@args) or die
693 "Error: " . $translator->error;
694
695 print $output;
696
697You could use L<Module::Find> to search for all subclasses in the MyDB::*
880a1a0c 698namespace, which is currently left as an exercise for the reader.
b0a20454 699
362500af 700=head2 Schema versioning
701
702The following example shows simplistically how you might use DBIx::Class to
703deploy versioned schemas to your customers. The basic process is as follows:
704
da4779ad 705=over 4
706
707=item 1.
708
709Create a DBIx::Class schema
710
711=item 2.
712
713Save the schema
714
715=item 3.
716
717Deploy to customers
718
719=item 4.
720
721Modify schema to change functionality
722
723=item 5.
724
725Deploy update to customers
726
727=back
362500af 728
729=head3 Create a DBIx::Class schema
730
731This can either be done manually, or generated from an existing database as
732described under C<Schema import/export>.
733
734=head3 Save the schema
735
736Use C<sqlt> to transform your schema into an SQL script suitable for your
737customer's database. E.g. for MySQL:
738
54c30987 739 sqlt --from SQL::Translator::Parser::DBIx::Class
362500af 740 --to MySQL
741 --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
742
743If you need to target databases from multiple vendors, just generate an SQL
744script suitable for each. To support PostgreSQL too:
745
54c30987 746 sqlt --from SQL::Translator::DBIx::Class
362500af 747 --to PostgreSQL
748 --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
749
750=head3 Deploy to customers
751
752There are several ways you could deploy your schema. These are probably
753beyond the scope of this recipe, but might include:
754
da4779ad 755=over 4
756
757=item 1.
758
759Require customer to apply manually using their RDBMS.
760
761=item 2.
762
763Package along with your app, making database dump/schema update/tests
362500af 764all part of your install.
765
da4779ad 766=back
767
362500af 768=head3 Modify the schema to change functionality
769
770As your application evolves, it may be necessary to modify your schema to
771change functionality. Once the changes are made to your schema in DBIx::Class,
772export the modified schema as before, taking care not to overwrite the original:
773
54c30987 774 sqlt --from SQL::Translator::DBIx::Class
362500af 775 --to MySQL
776 --DBIx::Class "Anything.pm" > Schema2.mysql.sql
777
778Next, use sqlt-diff to create an SQL script that will update the customer's
779database schema:
780
781 sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
782
783=head3 Deploy update to customers
784
785The schema update can be deployed to customers using the same method as before.
786
7be93b07 787=head2 Setting limit dialect for SQL::Abstract::Limit
788
324572ca 789In some cases, SQL::Abstract::Limit cannot determine the dialect of
790the remote SQL server by looking at the database handle. This is a
791common problem when using the DBD::JDBC, since the DBD-driver only
792know that in has a Java-driver available, not which JDBC driver the
793Java component has loaded. This specifically sets the limit_dialect
794to Microsoft SQL-server (See more names in SQL::Abstract::Limit
795-documentation.
7be93b07 796
797 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
798
324572ca 799The JDBC bridge is one way of getting access to a MSSQL server from a platform
7be93b07 800that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
801
324572ca 802=head2 Setting quoting for the generated SQL.
2437a1e3 803
324572ca 804If the database contains column names with spaces and/or reserved words, they
805need to be quoted in the SQL queries. This is done using:
2437a1e3 806
807 __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
808 __PACKAGE__->storage->sql_maker->name_sep('.');
809
324572ca 810The first sets the quote characters. Either a pair of matching
811brackets, or a C<"> or C<'>:
2437a1e3 812
813 __PACKAGE__->storage->sql_maker->quote_char('"');
814
324572ca 815Check the documentation of your database for the correct quote
816characters to use. C<name_sep> needs to be set to allow the SQL
817generator to put the quotes the correct place.
2437a1e3 818
086b93a2 819=head2 Overloading methods
820
821L<DBIx::Class> uses the L<Class::C3> package, which provides for redispatch of
822method calls. You have to use calls to C<next::method> to overload methods.
823More information on using L<Class::C3> with L<DBIx::Class> can be found in
824L<DBIx::Class::Manual::Component>.
825
826=head3 Changing one field whenever another changes
827
828For example, say that you have three columns, C<id>, C<number>, and
829C<squared>. You would like to make changes to C<number> and have
830C<squared> be automagically set to the value of C<number> squared.
831You can accomplish this by overriding C<store_column>:
832
833 sub store_column {
834 my ( $self, $name, $value ) = @_;
835 if ($name eq 'number') {
836 $self->squared($value * $value);
837 }
838 $self->next::method($name, $value);
839 }
840
841Note that the hard work is done by the call to C<next::method>, which
324572ca 842redispatches your call to store_column in the superclass(es).
086b93a2 843
844=head3 Automatically creating related objects
845
324572ca 846You might have a class C<Artist> which has many C<CD>s. Further, if you
086b93a2 847want to create a C<CD> object every time you insert an C<Artist> object.
ccbebdbc 848You can accomplish this by overriding C<insert> on your objects:
086b93a2 849
850 sub insert {
ccbebdbc 851 my ( $self, @args ) = @_;
852 $self->next::method(@args);
086b93a2 853 $self->cds->new({})->fill_from_artist($self)->insert;
854 return $self;
855 }
856
857where C<fill_from_artist> is a method you specify in C<CD> which sets
858values in C<CD> based on the data in the C<Artist> object you pass in.
859
1def3451 860=head2 Debugging DBIx::Class objects with Data::Dumper
861
862L<Data::Dumper> can be a very useful tool for debugging, but sometimes it can
863be hard to find the pertinent data in all the data it can generate.
864Specifically, if one naively tries to use it like so,
865
866 use Data::Dumper;
867
868 my $cd = $schema->resultset('CD')->find(1);
869 print Dumper($cd);
870
871several pages worth of data from the CD object's schema and result source will
872be dumped to the screen. Since usually one is only interested in a few column
873values of the object, this is not very helpful.
874
875Luckily, it is possible to modify the data before L<Data::Dumper> outputs
876it. Simply define a hook that L<Data::Dumper> will call on the object before
877dumping it. For example,
878
879 package My::DB::CD;
880
881 sub _dumper_hook {
99fb1058 882 $_[0] = bless {
883 %{ $_[0] },
1def3451 884 result_source => undef,
99fb1058 885 }, ref($_[0]);
1def3451 886 }
887
888 [...]
889
890 use Data::Dumper;
891
22139027 892 local $Data::Dumper::Freezer = '_dumper_hook';
1def3451 893
894 my $cd = $schema->resultset('CD')->find(1);
895 print Dumper($cd);
896 # dumps $cd without its ResultSource
897
898If the structure of your schema is such that there is a common base class for
899all your table classes, simply put a method similar to C<_dumper_hook> in the
900base class and set C<$Data::Dumper::Freezer> to its name and L<Data::Dumper>
901will automagically clean up your data before printing it. See
902L<Data::Dumper/EXAMPLES> for more information.
903
1def3451 904=head2 Retrieving a row object's Schema
905
324572ca 906It is possible to get a Schema object from a row object like so:
1def3451 907
908 my $schema = $cd->result_source->schema;
324572ca 909 # use the schema as normal:
910 my $artist_rs = $schema->resultset('Artist');
1def3451 911
912This can be useful when you don't want to pass around a Schema object to every
913method.
914
4c248161 915=head2 Profiling
916
917When you enable L<DBIx::Class::Storage::DBI>'s debugging it prints the SQL
918executed as well as notifications of query completion and transaction
919begin/commit. If you'd like to profile the SQL you can subclass the
920L<DBIx::Class::Storage::Statistics> class and write your own profiling
921mechanism:
922
923 package My::Profiler;
924 use strict;
925
926 use base 'DBIx::Class::Storage::Statistics';
927
928 use Time::HiRes qw(time);
929
930 my $start;
931
932 sub query_start {
933 my $self = shift();
934 my $sql = shift();
935 my $params = @_;
936
937 print "Executing $sql: ".join(', ', @params)."\n";
938 $start = time();
939 }
940
941 sub query_end {
942 my $self = shift();
943 my $sql = shift();
944 my @params = @_;
945
946 printf("Execution took %0.4f seconds.\n", time() - $start);
947 $start = undef;
948 }
949
950 1;
951
952You can then install that class as the debugging object:
953
954 __PACKAGE__->storage()->debugobj(new My::Profiler());
955 __PACKAGE__->storage()->debug(1);
956
957A more complicated example might involve storing each execution of SQL in an
958array:
959
960 sub query_end {
961 my $self = shift();
962 my $sql = shift();
963 my @params = @_;
964
965 my $elapsed = time() - $start;
966 push(@{ $calls{$sql} }, {
967 params => \@params,
968 elapsed => $elapsed
969 });
970 }
971
972You could then create average, high and low execution times for an SQL
973statement and dig down to see if certain parameters cause aberrant behavior.
974
e8e9e5c7 975=head2 Getting the value of the primary key for the last database insert
976
74413b83 977AKA getting last_insert_id
978
e8e9e5c7 979If you are using PK::Auto, this is straightforward:
980
74413b83 981 my $foo = $rs->create(\%blah);
e8e9e5c7 982 # do more stuff
983 my $id = $foo->id; # foo->my_primary_key_field will also work.
984
985If you are not using autoincrementing primary keys, this will probably
986not work, but then you already know the value of the last primary key anyway.
987
824f4422 988=head2 Dynamic Sub-classing DBIx::Class proxy classes
989(AKA multi-class object inflation from one table)
990
324572ca 991L<DBIx::Class> classes are proxy classes, therefore some different
992techniques need to be employed for more than basic subclassing. In
993this example we have a single user table that carries a boolean bit
994for admin. We would like like to give the admin users
995objects(L<DBIx::Class::Row>) the same methods as a regular user but
996also special admin only methods. It doesn't make sense to create two
997seperate proxy-class files for this. We would be copying all the user
998methods into the Admin class. There is a cleaner way to accomplish
999this.
1000
c6d147b6 1001Overriding the C<inflate_result> method within the User proxy-class
324572ca 1002gives us the effect we want. This method is called by
1003L<DBIx::Class::ResultSet> when inflating a result from storage. So we
1004grab the object being returned, inspect the values we are looking for,
1005bless it if it's an admin object, and then return it. See the example
1006below:
824f4422 1007
1008B<Schema Definition>
1009
1010 package DB::Schema;
1011
1012 use base qw/DBIx::Class::Schema/;
1013
1014 __PACKAGE__->load_classes(qw/User/);
1015
1016
1017B<Proxy-Class definitions>
1018
1019 package DB::Schema::User;
1020
1021 use strict;
1022 use warnings;
1023 use base qw/DBIx::Class/;
1024
1025 ### Defined what our admin class is for ensure_class_loaded
1026 my $admin_class = __PACKAGE__ . '::Admin';
1027
324572ca 1028 __PACKAGE__->load_components(qw/Core/);
824f4422 1029
1030 __PACKAGE__->table('users');
1031
1032 __PACKAGE__->add_columns(qw/user_id email password
1033 firstname lastname active
1034 admin/);
1035
1036 __PACKAGE__->set_primary_key('user_id');
1037
1038 sub inflate_result {
1039 my $self = shift;
1040 my $ret = $self->next::method(@_);
1041 if( $ret->admin ) {### If this is an admin rebless for extra functions
1042 $self->ensure_class_loaded( $admin_class );
1043 bless $ret, $admin_class;
1044 }
1045 return $ret;
1046 }
1047
1048 sub hello {
1049 print "I am a regular user.\n";
1050 return ;
1051 }
1052
1053
1054 package DB::Schema::User::Admin;
1055
1056 use strict;
1057 use warnings;
1058 use base qw/DB::Schema::User/;
1059
1060 sub hello
1061 {
1062 print "I am an admin.\n";
1063 return;
1064 }
1065
1066 sub do_admin_stuff
1067 {
1068 print "I am doing admin stuff\n";
1069 return ;
1070 }
1071
1072B<Test File> test.pl
1073
1074 use warnings;
1075 use strict;
1076 use DB::Schema;
1077
1078 my $user_data = { email => 'someguy@place.com',
1079 password => 'pass1',
1080 admin => 0 };
1081
1082 my $admin_data = { email => 'someadmin@adminplace.com',
1083 password => 'pass2',
1084 admin => 1 };
1085
1086 my $schema = DB::Schema->connection('dbi:Pg:dbname=test');
1087
1088 $schema->resultset('User')->create( $user_data );
1089 $schema->resultset('User')->create( $admin_data );
1090
1091 ### Now we search for them
1092 my $user = $schema->resultset('User')->single( $user_data );
1093 my $admin = $schema->resultset('User')->single( $admin_data );
1094
1095 print ref $user, "\n";
1096 print ref $admin, "\n";
1097
1098 print $user->password , "\n"; # pass1
1099 print $admin->password , "\n";# pass2; inherited from User
1100 print $user->hello , "\n";# I am a regular user.
1101 print $admin->hello, "\n";# I am an admin.
1102
1103 ### The statement below will NOT print
1104 print "I can do admin stuff\n" if $user->can('do_admin_stuff');
1105 ### The statement below will print
1106 print "I can do admin stuff\n" if $admin->can('do_admin_stuff');
1107
fe5cf259 1108=head2 Skip object creation for faster results
1109
1110DBIx::Class is not built for speed, it's built for convenience and
1111ease of use, but sometimes you just need to get the data, and skip the
1112fancy objects. Luckily this is also fairly easy using
1113C<inflate_result>:
1114
1115 # Define a class which just returns the results as a hashref:
1116 package My::HashRefInflator;
1117
1118 ## $me is the hashref of cols/data from the immediate resultsource
1119 ## $prefetch is a deep hashref of all the data from the prefetched
1120 ## related sources.
1121
1122 sub mk_hash {
1123 my ($me, $rest) = @_;
1124
1125 return { %$me,
4bbcc5ed 1126 map { ($_ => mk_hash(@{$rest->{$_}})) } keys %$rest
fe5cf259 1127 };
1128 }
1129
1130 sub inflate_result {
1131 my ($self, $source, $me, $prefetch) = @_;
1132 return mk_hash($me, $prefetch);
1133 }
1134
1135 # Change the object inflation to a hashref for just this resultset:
1136 $rs->result_class('My::HashRefInflator');
1137
1138 my $datahashref = $rs->next;
4bbcc5ed 1139 foreach my $col (keys %$datahashref) {
a4482862 1140 if(!ref($datahashref->{$col})) {
fe5cf259 1141 # It's a plain value
1142 }
1143 elsif(ref($datahashref->{$col} eq 'HASH')) {
1144 # It's a related value in a hashref
1145 }
1146 }
1147
9e4c2514 1148=head2 Want to know if find_or_create found or created a row?
1149
1150Just use C<find_or_new> instead, then check C<in_storage>:
fe5cf259 1151
9e4c2514 1152 my $obj = $rs->find_or_new({ blah => 'blarg' });
1153 unless ($obj->in_storage) {
1154 $obj->insert;
1155 # do whatever else you wanted if it was a new row
1156 }
1157
7aaec96c 1158=head3 Wrapping/overloading a column accessor
1159
1160Problem: Say you have a table "Camera" and want to associate a description
1161with each camera. For most cameras, you'll be able to generate the description from
1162the other columns. However, in a few special cases you may want to associate a
1163custom description with a camera.
1164
1165Solution:
1166
1167In your database schema, define a description field in the "Camera" table that
1168can contain text and null values.
1169
1170In DBIC, we'll overload the column accessor to provide a sane default if no
1171custom description is defined. The accessor will either return or generate the
1172description, depending on whether the field is null or not.
1173
1174First, in your "Camera" schema class, define the description field as follows:
1175
1176 __PACKAGE__->add_columns(description => { accessor => '_description' });
1177
1178Next, we'll define the accessor-wrapper subroutine:
1179
1180 sub description {
1181 my $self = shift;
1182
1183 # If there is an update to the column, we'll let the original accessor
1184 # deal with it.
1185 return $self->_description(@_) if @_;
1186
1187 # Fetch the column value.
1188 my $description = $self->_description;
1189
1190 # If there's something in the description field, then just return that.
1191 return $description if defined $description && length $descripton;
1192
1193 # Otherwise, generate a description.
1194 return $self->generate_description;
1195 }
1196
9e4c2514 1197=cut