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