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