Minor typo fix in schema manual
[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
35d4fe78 355L<DBIx::Class::Storage::DBI>. Here is an example of the recommended
40dbc108 356way to use it:
87980de7 357
35d4fe78 358 my $genus = Genus->find(12);
359 eval {
360 MyDB->txn_begin;
361 $genus->add_to_species({ name => 'troglodyte' });
362 $genus->wings(2);
363 $genus->update;
364 cromulate($genus); # Can have a nested transation
365 MyDB->txn_commit;
366 };
367 if ($@) {
368 # Rollback might fail, too
87980de7 369 eval {
35d4fe78 370 MyDB->txn_rollback
87980de7 371 };
35d4fe78 372 }
87980de7 373
40dbc108 374Currently, a nested commit will do nothing and a nested rollback will
35d4fe78 375die. The code at each level must be sure to call rollback in the case
40dbc108 376of an error, to ensure that the rollback will propagate to the top
35d4fe78 377level and be issued. Support for savepoints and for true nested
40dbc108 378transactions (for databases that support them) will hopefully be added
379in the future.
ee38fa40 380
130c6439 381=head2 Many-to-many relationships
ee38fa40 382
ea6309e2 383This is straightforward using L<DBIx::Class::Relationship::ManyToMany>:
384
bade79c4 385 package My::DB;
386 # ... set up connection ...
387
388 package My::User;
389 use base 'My::DB';
390 __PACKAGE__->table('user');
391 __PACKAGE__->add_columns(qw/id name/);
392 __PACKAGE__->set_primary_key('id');
393 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
394 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
395
396 package My::UserAddress;
397 use base 'My::DB';
398 __PACKAGE__->table('user_address');
399 __PACKAGE__->add_columns(qw/user address/);
400 __PACKAGE__->set_primary_key(qw/user address/);
401 __PACKAGE__->belongs_to('user' => 'My::User');
402 __PACKAGE__->belongs_to('address' => 'My::Address');
403
404 package My::Address;
405 use base 'My::DB';
406 __PACKAGE__->table('address');
407 __PACKAGE__->add_columns(qw/id street town area_code country/);
408 __PACKAGE__->set_primary_key('id');
409 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
410 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
411
412 $rs = $user->addresses(); # get all addresses for a user
413 $rs = $address->users(); # get all users for an address
414
415=head2 Setting default values for a row
a00e1684 416
35d4fe78 417It's as simple as overriding the C<new> method. Note the use of
40dbc108 418C<next::method>.
a00e1684 419
35d4fe78 420 sub new {
421 my ( $class, $attrs ) = @_;
40dbc108 422
35d4fe78 423 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
40dbc108 424
35d4fe78 425 $class->next::method($attrs);
426 }
a00e1684 427
25af00d7 428=head2 Stringification
429
40dbc108 430Employ the standard stringification technique by using the C<overload>
35d4fe78 431module. Replace C<foo> with the column/method of your choice.
25af00d7 432
35d4fe78 433 use overload '""' => 'foo', fallback => 1;
25af00d7 434
bade79c4 435=head2 Disconnecting cleanly
436
437If you find yourself quitting an app with Control-C a lot during
438development, you might like to put the following signal handler in
439your main database class to make sure it disconnects cleanly:
440
441 $SIG{INT} = sub {
442 __PACKAGE__->storage->dbh->disconnect;
443 };
444
362500af 445=head2 Schema import/export
446
447This functionality requires you to have L<SQL::Translator> (also known as
448"SQL Fairy") installed.
449
450To create a DBIx::Class schema from an existing database:
451
452 sqlt --from DBI
453 --to DBIx::Class::File
454 --prefix "MySchema" > MySchema.pm
455
456To create a MySQL database from an existing L<DBIx::Class> schema, convert the
457schema to MySQL's dialect of SQL:
458
459 sqlt --from DBIx::Class --to MySQL --DBIx::Class "MySchema.pm" > Schema1.sql
460
461And import using the mysql client:
462
463 mysql -h "host" -D "database" -u "user" -p < Schema1.sql
464
b0a20454 465=head2 Easy migration from class-based to schema-based setup
466
467You want to start using the schema-based approach to L<DBIx::Class>
468(see L<SchemaIntro.pod>), but have an established class-based setup with lots
469of existing classes that you don't want to move by hand. Try this nifty script
470instead:
471
472 use MyDB;
473 use SQL::Translator;
474
475 my $schema = MyDB->schema_instance;
476
477 my $translator = SQL::Translator->new(
478 debug => $debug || 0,
479 trace => $trace || 0,
480 no_comments => $no_comments || 0,
481 show_warnings => $show_warnings || 0,
482 add_drop_table => $add_drop_table || 0,
483 validate => $validate || 0,
484 parser_args => {
485 'DBIx::Schema' => $schema,
486 }
487 producer_args => {
488 'prefix' => 'My::Schema',
489 }
490 );
491
492 $translator->parser('DBIx::Class');
493 $translator->producer('DBIx::Class::File');
494
495 my $output = $translator->translate(@args) or die
496 "Error: " . $translator->error;
497
498 print $output;
499
500You could use L<Module::Find> to search for all subclasses in the MyDB::*
501namespace, which is currently left as an excercise for the reader.
502
362500af 503=head2 Schema versioning
504
505The following example shows simplistically how you might use DBIx::Class to
506deploy versioned schemas to your customers. The basic process is as follows:
507
5081) Create a DBIx::Class schema
5092) Save the schema
5103) Deploy to customers
5114) Modify schema to change functionality
5125) Deploy update to customers
513
514=head3 Create a DBIx::Class schema
515
516This can either be done manually, or generated from an existing database as
517described under C<Schema import/export>.
518
519=head3 Save the schema
520
521Use C<sqlt> to transform your schema into an SQL script suitable for your
522customer's database. E.g. for MySQL:
523
524 sqlt --from DBIx::Class
525 --to MySQL
526 --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
527
528If you need to target databases from multiple vendors, just generate an SQL
529script suitable for each. To support PostgreSQL too:
530
531 sqlt --from DBIx::Class
532 --to PostgreSQL
533 --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
534
535=head3 Deploy to customers
536
537There are several ways you could deploy your schema. These are probably
538beyond the scope of this recipe, but might include:
539
5401) Require customer to apply manually using their RDBMS.
5412) Package along with your app, making database dump/schema update/tests
542all part of your install.
543
544=head3 Modify the schema to change functionality
545
546As your application evolves, it may be necessary to modify your schema to
547change functionality. Once the changes are made to your schema in DBIx::Class,
548export the modified schema as before, taking care not to overwrite the original:
549
550 sqlt --from DBIx::Class
551 --to MySQL
552 --DBIx::Class "Anything.pm" > Schema2.mysql.sql
553
554Next, use sqlt-diff to create an SQL script that will update the customer's
555database schema:
556
557 sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
558
559=head3 Deploy update to customers
560
561The schema update can be deployed to customers using the same method as before.
562
7be93b07 563=head2 Setting limit dialect for SQL::Abstract::Limit
564
565In some cases, SQL::Abstract::Limit cannot determine the dialect of the remote
566SQL-server by looking at the database-handle. This is a common problem when
567using the DBD::JDBC, since the DBD-driver only know that in has a Java-driver
568available, not which JDBC-driver the Java component has loaded.
569This specifically sets the limit_dialect to Microsoft SQL-server (Se more names
570in SQL::Abstract::Limit -documentation.
571
572 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
573
574The JDBC-bridge is one way of getting access to a MSSQL-server from a platform
575that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
576
40dbc108 577=cut