Fixup to Cursor, updated Changes
[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
bade79c4 75When you only want selected columns from a table, you can use C<cols> to
76specify which ones you need:
faf62551 77
bade79c4 78 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 79 undef,
bade79c4 80 {
5e8b1b2a 81 columns => [qw/ name /]
bade79c4 82 }
83 );
faf62551 84
bade79c4 85 # Equivalent SQL:
86 # SELECT artist.name FROM artist
faf62551 87
bade79c4 88=head3 Using database functions or stored procedures
faf62551 89
bade79c4 90The combination of C<select> and C<as> can be used to return the result of a
91database function or stored procedure as a column value. You use C<select> to
92specify the source for your column value (e.g. a column name, function, or
93stored procedure name). You then use C<as> to set the column name you will use
94to access the returned value:
faf62551 95
bade79c4 96 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 97 undef,
bade79c4 98 {
99 select => [ 'name', { LENGTH => 'name' } ],
100 as => [qw/ name name_length /],
101 }
102 );
faf62551 103
bade79c4 104 # Equivalent SQL:
105 # SELECT name name, LENGTH( name ) name_length
106 # FROM artist
faf62551 107
108If your alias exists as a column in your base class (i.e. it was added with
bade79c4 109C<add_columns>), you just access it as normal. Our C<Artist> class has a C<name>
110column, so we just use the C<name> accessor:
faf62551 111
bade79c4 112 my $artist = $rs->first();
113 my $name = $artist->name();
faf62551 114
115If on the other hand the alias does not correspond to an existing column, you
bade79c4 116can get the value using the C<get_column> accessor:
faf62551 117
bade79c4 118 my $name_length = $artist->get_column('name_length');
faf62551 119
bade79c4 120If you don't like using C<get_column>, you can always create an accessor for
faf62551 121any of your aliases using either of these:
122
bade79c4 123 # Define accessor manually:
124 sub name_length { shift->get_column('name_length'); }
faf62551 125
bade79c4 126 # Or use DBIx::Class::AccessorGroup:
127 __PACKAGE__->mk_group_accessors('column' => 'name_length');
faf62551 128
bade79c4 129=head3 SELECT DISTINCT with multiple columns
faf62551 130
bade79c4 131 my $rs = $schema->resultset('Foo')->search(
5e8b1b2a 132 undef,
bade79c4 133 {
134 select => [
135 { distinct => [ $source->columns ] }
136 ],
137 as => [ $source->columns ]
138 }
139 );
faf62551 140
bade79c4 141=head3 SELECT COUNT(DISTINCT colname)
6607ee1b 142
bade79c4 143 my $rs = $schema->resultset('Foo')->search(
5e8b1b2a 144 undef,
bade79c4 145 {
146 select => [
147 { count => { distinct => 'colname' } }
148 ],
149 as => [ 'count' ]
150 }
151 );
6607ee1b 152
bade79c4 153=head3 Grouping results
154
155L<DBIx::Class> supports C<GROUP BY> as follows:
156
157 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 158 undef,
bade79c4 159 {
160 join => [qw/ cds /],
161 select => [ 'name', { count => 'cds.cdid' } ],
162 as => [qw/ name cd_count /],
163 group_by => [qw/ name /]
164 }
165 );
6607ee1b 166
bade79c4 167 # Equivalent SQL:
168 # SELECT name, COUNT( cds.cdid ) FROM artist me
169 # LEFT JOIN cd cds ON ( cds.artist = me.artistid )
170 # GROUP BY name
6607ee1b 171
74dc2edc 172=head3 Predefined searches
173
174You can write your own DBIx::Class::ResultSet class by inheriting from it
175and define often used searches as methods:
176
177 package My::DBIC::ResultSet::CD;
178 use strict;
179 use warnings;
180 use base 'DBIx::Class::ResultSet';
181
182 sub search_cds_ordered {
183 my ($self) = @_;
184
185 return $self->search(
186 {},
187 { order_by => 'name DESC' },
188 );
189 }
190
191 1;
192
193To use your resultset, first tell DBIx::Class to create an instance of it
194for you, in your My::DBIC::Schema::CD class:
195
196 __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
197
198Then call your new method in your code:
199
200 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
201
202
d6ed6a67 203=head3 Predefined searches without writing a ResultSet class
204
205Alternatively you can automatically generate a DBIx::Class::ResultSet
206class by using the ResultSetManager component and tagging your method
207as ResultSet:
208
209 __PACKAGE__->load_components(qw/ ResultSetManager Core /);
210
211 sub search_cds_ordered : ResultSet {
212 my ($self) = @_;
213 return $self->search(
214 {},
215 { order_by => 'name DESC' },
216 );
217 }
218
219Then call your method in the same way from your code:
220
221 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
222
87980de7 223=head2 Using joins and prefetch
224
bade79c4 225You can use the C<join> attribute to allow searching on, or sorting your
226results by, one or more columns in a related table. To return all CDs matching
227a particular artist name:
ea6309e2 228
bade79c4 229 my $rs = $schema->resultset('CD')->search(
230 {
231 'artist.name' => 'Bob Marley'
232 },
233 {
234 join => [qw/artist/], # join the artist table
235 }
236 );
237
238 # Equivalent SQL:
239 # SELECT cd.* FROM cd
240 # JOIN artist ON cd.artist = artist.id
241 # WHERE artist.name = 'Bob Marley'
242
243If required, you can now sort on any column in the related tables by including
244it in your C<order_by> attribute:
245
246 my $rs = $schema->resultset('CD')->search(
247 {
248 'artist.name' => 'Bob Marley'
249 },
250 {
251 join => [qw/ artist /],
252 order_by => [qw/ artist.name /]
253 }
254 };
ea6309e2 255
bade79c4 256 # Equivalent SQL:
257 # SELECT cd.* FROM cd
258 # JOIN artist ON cd.artist = artist.id
259 # WHERE artist.name = 'Bob Marley'
260 # ORDER BY artist.name
ea6309e2 261
bade79c4 262Note that the C<join> attribute should only be used when you need to search or
263sort using columns in a related table. Joining related tables when you only
264need columns from the main table will make performance worse!
ea6309e2 265
bade79c4 266Now let's say you want to display a list of CDs, each with the name of the
267artist. The following will work fine:
ea6309e2 268
bade79c4 269 while (my $cd = $rs->next) {
270 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
271 }
ea6309e2 272
bade79c4 273There is a problem however. We have searched both the C<cd> and C<artist> tables
274in our main query, but we have only returned data from the C<cd> table. To get
275the artist name for any of the CD objects returned, L<DBIx::Class> will go back
276to the database:
ea6309e2 277
bade79c4 278 SELECT artist.* FROM artist WHERE artist.id = ?
ea6309e2 279
280A statement like the one above will run for each and every CD returned by our
281main query. Five CDs, five extra queries. A hundred CDs, one hundred extra
282queries!
283
bade79c4 284Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem.
897342e4 285This allows you to fetch results from related tables in advance:
ea6309e2 286
bade79c4 287 my $rs = $schema->resultset('CD')->search(
288 {
289 'artist.name' => 'Bob Marley'
290 },
291 {
292 join => [qw/ artist /],
293 order_by => [qw/ artist.name /],
294 prefetch => [qw/ artist /] # return artist data too!
295 }
296 );
ea6309e2 297
bade79c4 298 # Equivalent SQL (note SELECT from both "cd" and "artist"):
299 # SELECT cd.*, artist.* FROM cd
300 # JOIN artist ON cd.artist = artist.id
301 # WHERE artist.name = 'Bob Marley'
302 # ORDER BY artist.name
ea6309e2 303
304The code to print the CD list remains the same:
305
bade79c4 306 while (my $cd = $rs->next) {
307 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
308 }
ea6309e2 309
bade79c4 310L<DBIx::Class> has now prefetched all matching data from the C<artist> table,
ea6309e2 311so no additional SQL statements are executed. You now have a much more
312efficient query.
313
bade79c4 314Note that as of L<DBIx::Class> 0.04, C<prefetch> cannot be used with
315C<has_many> relationships. You will get an error along the lines of "No
316accessor for prefetched ..." if you try.
ea6309e2 317
bade79c4 318Also note that C<prefetch> should only be used when you know you will
ea6309e2 319definitely use data from a related table. Pre-fetching related tables when you
320only need columns from the main table will make performance worse!
321
bade79c4 322=head3 Multi-step joins
ea6309e2 323
324Sometimes you want to join more than one relationship deep. In this example,
bade79c4 325we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes>
326contain a specific string:
327
328 # Relationships defined elsewhere:
329 # Artist->has_many('cds' => 'CD', 'artist');
330 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
331
332 my $rs = $schema->resultset('Artist')->search(
333 {
334 'liner_notes.notes' => { 'like', '%some text%' },
335 },
336 {
337 join => {
338 'cds' => 'liner_notes'
339 }
340 }
341 );
ea6309e2 342
bade79c4 343 # Equivalent SQL:
344 # SELECT artist.* FROM artist
345 # JOIN ( cd ON artist.id = cd.artist )
346 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
347 # WHERE liner_notes.notes LIKE '%some text%'
ea6309e2 348
349Joins can be nested to an arbitrary level. So if we decide later that we
350want to reduce the number of Artists returned based on who wrote the liner
351notes:
352
bade79c4 353 # Relationship defined elsewhere:
354 # LinerNotes->belongs_to('author' => 'Person');
355
356 my $rs = $schema->resultset('Artist')->search(
357 {
358 'liner_notes.notes' => { 'like', '%some text%' },
359 'author.name' => 'A. Writer'
360 },
361 {
362 join => {
363 'cds' => {
364 'liner_notes' => 'author'
ea6309e2 365 }
bade79c4 366 }
367 }
368 );
ea6309e2 369
bade79c4 370 # Equivalent SQL:
371 # SELECT artist.* FROM artist
372 # JOIN ( cd ON artist.id = cd.artist )
373 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
374 # JOIN ( author ON author.id = liner_notes.author )
375 # WHERE liner_notes.notes LIKE '%some text%'
376 # AND author.name = 'A. Writer'
87980de7 377
897342e4 378=head2 Multi-step prefetch
379
380From 0.04999_05 onwards, C<prefetch> can be nested more than one relationship
381deep using the same syntax as a multi-step join:
382
383 my $rs = $schema->resultset('Tag')->search(
5e8b1b2a 384 undef,
897342e4 385 {
386 prefetch => {
387 cd => 'artist'
388 }
389 }
390 );
391
392 # Equivalent SQL:
393 # SELECT tag.*, cd.*, artist.* FROM tag
394 # JOIN cd ON tag.cd = cd.cdid
395 # JOIN artist ON cd.artist = artist.artistid
396
397Now accessing our C<cd> and C<artist> relationships does not need additional
398SQL statements:
399
400 my $tag = $rs->first;
401 print $tag->cd->artist->name;
402
87980de7 403=head2 Transactions
404
405As of version 0.04001, there is improved transaction support in
181a28f4 406L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>. Here is an
407example of the recommended way to use it:
87980de7 408
181a28f4 409 my $genus = $schema->resultset('Genus')->find(12);
410
411 my $coderef1 = sub {
412 my ($schema, $genus, $code) = @_;
35d4fe78 413 $genus->add_to_species({ name => 'troglodyte' });
414 $genus->wings(2);
415 $genus->update;
880a1a0c 416 $schema->txn_do($code, $genus); # Can have a nested transaction
181a28f4 417 return $genus->species;
418 };
419
420 my $coderef2 = sub {
421 my ($genus) = @_;
422 $genus->extinct(1);
423 $genus->update;
35d4fe78 424 };
181a28f4 425
426 my $rs;
427 eval {
428 $rs = $schema->txn_do($coderef1, $schema, $genus, $coderef2);
429 };
430
431 if ($@) { # Transaction failed
432 die "the sky is falling!" #
433 if ($@ =~ /Rollback failed/); # Rollback failed
434
435 deal_with_failed_transaction();
35d4fe78 436 }
87980de7 437
181a28f4 438Nested transactions will work as expected. That is, only the outermost
439transaction will actually issue a commit to the $dbh, and a rollback
440at any level of any transaction will cause the entire nested
441transaction to fail. Support for savepoints and for true nested
40dbc108 442transactions (for databases that support them) will hopefully be added
443in the future.
ee38fa40 444
130c6439 445=head2 Many-to-many relationships
ee38fa40 446
ea6309e2 447This is straightforward using L<DBIx::Class::Relationship::ManyToMany>:
448
bade79c4 449 package My::DB;
450 # ... set up connection ...
451
452 package My::User;
453 use base 'My::DB';
454 __PACKAGE__->table('user');
455 __PACKAGE__->add_columns(qw/id name/);
456 __PACKAGE__->set_primary_key('id');
457 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
458 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
459
460 package My::UserAddress;
461 use base 'My::DB';
462 __PACKAGE__->table('user_address');
463 __PACKAGE__->add_columns(qw/user address/);
464 __PACKAGE__->set_primary_key(qw/user address/);
465 __PACKAGE__->belongs_to('user' => 'My::User');
466 __PACKAGE__->belongs_to('address' => 'My::Address');
467
468 package My::Address;
469 use base 'My::DB';
470 __PACKAGE__->table('address');
471 __PACKAGE__->add_columns(qw/id street town area_code country/);
472 __PACKAGE__->set_primary_key('id');
473 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
474 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
475
476 $rs = $user->addresses(); # get all addresses for a user
477 $rs = $address->users(); # get all users for an address
478
479=head2 Setting default values for a row
a00e1684 480
35d4fe78 481It's as simple as overriding the C<new> method. Note the use of
40dbc108 482C<next::method>.
a00e1684 483
35d4fe78 484 sub new {
485 my ( $class, $attrs ) = @_;
40dbc108 486
35d4fe78 487 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
40dbc108 488
35d4fe78 489 $class->next::method($attrs);
490 }
a00e1684 491
4a3c6354 492For more information about C<next::method>, look in the L<Class::C3>
493documentation. See also L<DBIx::Class::Manual::Component> for more
494ways to write your own base classes to do this.
495
496People looking for ways to do "triggers" with DBIx::Class are probably
497just looking for this.
498
25af00d7 499=head2 Stringification
500
40dbc108 501Employ the standard stringification technique by using the C<overload>
35d4fe78 502module. Replace C<foo> with the column/method of your choice.
25af00d7 503
35d4fe78 504 use overload '""' => 'foo', fallback => 1;
25af00d7 505
bade79c4 506=head2 Disconnecting cleanly
507
508If you find yourself quitting an app with Control-C a lot during
509development, you might like to put the following signal handler in
510your main database class to make sure it disconnects cleanly:
511
512 $SIG{INT} = sub {
6d1bf0a9 513 __PACKAGE__->storage->disconnect;
bade79c4 514 };
515
362500af 516=head2 Schema import/export
517
518This functionality requires you to have L<SQL::Translator> (also known as
519"SQL Fairy") installed.
520
521To create a DBIx::Class schema from an existing database:
522
523 sqlt --from DBI
524 --to DBIx::Class::File
525 --prefix "MySchema" > MySchema.pm
526
527To create a MySQL database from an existing L<DBIx::Class> schema, convert the
528schema to MySQL's dialect of SQL:
529
530 sqlt --from DBIx::Class --to MySQL --DBIx::Class "MySchema.pm" > Schema1.sql
531
532And import using the mysql client:
533
534 mysql -h "host" -D "database" -u "user" -p < Schema1.sql
535
b0a20454 536=head2 Easy migration from class-based to schema-based setup
537
538You want to start using the schema-based approach to L<DBIx::Class>
539(see L<SchemaIntro.pod>), but have an established class-based setup with lots
540of existing classes that you don't want to move by hand. Try this nifty script
541instead:
542
543 use MyDB;
544 use SQL::Translator;
545
546 my $schema = MyDB->schema_instance;
547
548 my $translator = SQL::Translator->new(
549 debug => $debug || 0,
550 trace => $trace || 0,
551 no_comments => $no_comments || 0,
552 show_warnings => $show_warnings || 0,
553 add_drop_table => $add_drop_table || 0,
554 validate => $validate || 0,
555 parser_args => {
556 'DBIx::Schema' => $schema,
c5f36986 557 },
b0a20454 558 producer_args => {
559 'prefix' => 'My::Schema',
c5f36986 560 },
b0a20454 561 );
562
563 $translator->parser('DBIx::Class');
564 $translator->producer('DBIx::Class::File');
565
566 my $output = $translator->translate(@args) or die
567 "Error: " . $translator->error;
568
569 print $output;
570
571You could use L<Module::Find> to search for all subclasses in the MyDB::*
880a1a0c 572namespace, which is currently left as an exercise for the reader.
b0a20454 573
362500af 574=head2 Schema versioning
575
576The following example shows simplistically how you might use DBIx::Class to
577deploy versioned schemas to your customers. The basic process is as follows:
578
da4779ad 579=over 4
580
581=item 1.
582
583Create a DBIx::Class schema
584
585=item 2.
586
587Save the schema
588
589=item 3.
590
591Deploy to customers
592
593=item 4.
594
595Modify schema to change functionality
596
597=item 5.
598
599Deploy update to customers
600
601=back
362500af 602
603=head3 Create a DBIx::Class schema
604
605This can either be done manually, or generated from an existing database as
606described under C<Schema import/export>.
607
608=head3 Save the schema
609
610Use C<sqlt> to transform your schema into an SQL script suitable for your
611customer's database. E.g. for MySQL:
612
613 sqlt --from DBIx::Class
614 --to MySQL
615 --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
616
617If you need to target databases from multiple vendors, just generate an SQL
618script suitable for each. To support PostgreSQL too:
619
620 sqlt --from DBIx::Class
621 --to PostgreSQL
622 --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
623
624=head3 Deploy to customers
625
626There are several ways you could deploy your schema. These are probably
627beyond the scope of this recipe, but might include:
628
da4779ad 629=over 4
630
631=item 1.
632
633Require customer to apply manually using their RDBMS.
634
635=item 2.
636
637Package along with your app, making database dump/schema update/tests
362500af 638all part of your install.
639
da4779ad 640=back
641
362500af 642=head3 Modify the schema to change functionality
643
644As your application evolves, it may be necessary to modify your schema to
645change functionality. Once the changes are made to your schema in DBIx::Class,
646export the modified schema as before, taking care not to overwrite the original:
647
648 sqlt --from DBIx::Class
649 --to MySQL
650 --DBIx::Class "Anything.pm" > Schema2.mysql.sql
651
652Next, use sqlt-diff to create an SQL script that will update the customer's
653database schema:
654
655 sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
656
657=head3 Deploy update to customers
658
659The schema update can be deployed to customers using the same method as before.
660
7be93b07 661=head2 Setting limit dialect for SQL::Abstract::Limit
662
663In some cases, SQL::Abstract::Limit cannot determine the dialect of the remote
664SQL-server by looking at the database-handle. This is a common problem when
665using the DBD::JDBC, since the DBD-driver only know that in has a Java-driver
666available, not which JDBC-driver the Java component has loaded.
667This specifically sets the limit_dialect to Microsoft SQL-server (Se more names
668in SQL::Abstract::Limit -documentation.
669
670 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
671
672The JDBC-bridge is one way of getting access to a MSSQL-server from a platform
673that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
674
2437a1e3 675=head2 Setting quotes for the generated SQL.
676
677If the database contains columnames with spaces and/or reserved words, the
678SQL-query needs to be quoted. This is done using:
679
680 __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
681 __PACKAGE__->storage->sql_maker->name_sep('.');
682
683The first sets the quotesymbols. If the quote i "symmetric" as " or '
684
685 __PACKAGE__->storage->sql_maker->quote_char('"');
686
880a1a0c 687is enough. If the left quote differs form the right quote, the first
2437a1e3 688notation should be used. name_sep needs to be set to allow the
689SQL generator to put the quotes the correct place.
690
40dbc108 691=cut