Merge 'trunk' into 'DBIx-Class-current'
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Manual / Cookbook.pod
1 =head1 NAME 
2
3 DBIx::Class::Manual::Cookbook - Miscellaneous recipes
4
5 =head1 RECIPES
6
7 =head2 Searching
8
9 =head3 Paged results
10
11 When you expect a large number of results, you can ask L<DBIx::Class> for a
12 paged resultset, which will fetch only a small number of records at a time:
13
14   my $rs = $schema->resultset('Artist')->search(
15     undef,
16     {
17       page => 1,  # page to return (defaults to 1)
18       rows => 10, # number of results per page
19     },
20   );
21
22   return $rs->all(); # all records for page 1
23
24 The C<page> attribute does not have to be specified in your search:
25
26   my $rs = $schema->resultset('Artist')->search(
27     undef,
28     {
29       rows => 10,
30     }
31   );
32
33   return $rs->page(1); # DBIx::Class::ResultSet containing first 10 records
34
35 In either of the above cases, you can return a L<Data::Page> object for the
36 resultset (suitable for use in e.g. a template) using the C<pager> method:
37
38   return $rs->pager();
39
40 =head3 Complex WHERE clauses
41
42 Sometimes you need to formulate a query using specific operators:
43
44   my @albums = $schema->resultset('Album')->search({
45     artist => { 'like', '%Lamb%' },
46     title  => { 'like', '%Fear of Fours%' },
47   });
48
49 This results in something like the following C<WHERE> clause:
50
51   WHERE artist LIKE '%Lamb%' AND title LIKE '%Fear of Fours%'
52
53 Other queries might require slightly more complex logic:
54
55   my @albums = $schema->resultset('Album')->search({
56     -or => [
57       -and => [
58         artist => { 'like', '%Smashing Pumpkins%' },
59         title  => 'Siamese Dream',
60       ],
61       artist => 'Starchildren',
62     ],
63   });
64
65 This results in the following C<WHERE> clause:
66
67   WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' )
68     OR artist = 'Starchildren'
69
70 For more information on generating complex queries, see
71 L<SQL::Abstract/WHERE CLAUSES>.
72
73 =head3 Using specific columns
74
75 When you only want selected columns from a table, you can use C<cols> to
76 specify which ones you need:
77
78   my $rs = $schema->resultset('Artist')->search(
79     undef,
80     {
81       columns => [qw/ name /]
82     }
83   );
84
85   # Equivalent SQL:
86   # SELECT artist.name FROM artist
87
88 =head3 Using database functions or stored procedures
89
90 The combination of C<select> and C<as> can be used to return the result of a
91 database function or stored procedure as a column value. You use C<select> to
92 specify the source for your column value (e.g. a column name, function, or
93 stored procedure name). You then use C<as> to set the column name you will use
94 to access the returned value:
95
96   my $rs = $schema->resultset('Artist')->search(
97     undef,
98     {
99       select => [ 'name', { LENGTH => 'name' } ],
100       as     => [qw/ name name_length /],
101     }
102   );
103
104   # Equivalent SQL:
105   # SELECT name name, LENGTH( name ) name_length
106   # FROM artist
107
108 If your alias exists as a column in your base class (i.e. it was added with
109 C<add_columns>), you just access it as normal. Our C<Artist> class has a C<name>
110 column, so we just use the C<name> accessor:
111
112   my $artist = $rs->first();
113   my $name = $artist->name();
114
115 If on the other hand the alias does not correspond to an existing column, you
116 can get the value using the C<get_column> accessor:
117
118   my $name_length = $artist->get_column('name_length');
119
120 If you don't like using C<get_column>, you can always create an accessor for
121 any of your aliases using either of these:
122
123   # Define accessor manually:
124   sub name_length { shift->get_column('name_length'); }
125     
126   # Or use DBIx::Class::AccessorGroup:
127   __PACKAGE__->mk_group_accessors('column' => 'name_length');
128
129 =head3 SELECT DISTINCT with multiple columns
130
131   my $rs = $schema->resultset('Foo')->search(
132     undef,
133     {
134       select => [
135         { distinct => [ $source->columns ] }
136       ],
137       as => [ $source->columns ]
138     }
139   );
140
141   my $count = $rs->next->get_column('count');
142
143 =head3 SELECT COUNT(DISTINCT colname)
144
145   my $rs = $schema->resultset('Foo')->search(
146     undef,
147     {
148       select => [
149         { count => { distinct => 'colname' } }
150       ],
151       as => [ 'count' ]
152     }
153   );
154
155 =head3 Grouping results
156
157 L<DBIx::Class> supports C<GROUP BY> as follows:
158
159   my $rs = $schema->resultset('Artist')->search(
160     undef,
161     {
162       join     => [qw/ cds /],
163       select   => [ 'name', { count => 'cds.cdid' } ],
164       as       => [qw/ name cd_count /],
165       group_by => [qw/ name /]
166     }
167   );
168
169   # Equivalent SQL:
170   # SELECT name, COUNT( cds.cdid ) FROM artist me
171   # LEFT JOIN cd cds ON ( cds.artist = me.artistid )
172   # GROUP BY name
173
174 =head3 Predefined searches
175
176 You can write your own DBIx::Class::ResultSet class by inheriting from it
177 and define often used searches as methods:
178
179   package My::DBIC::ResultSet::CD;
180   use strict;
181   use warnings;
182   use base 'DBIx::Class::ResultSet';
183
184   sub search_cds_ordered {
185       my ($self) = @_;
186
187       return $self->search(
188           {},
189           { order_by => 'name DESC' },
190       );
191   }
192
193   1;
194
195 To use your resultset, first tell DBIx::Class to create an instance of it
196 for you, in your My::DBIC::Schema::CD class:
197
198   __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
199
200 Then call your new method in your code:
201
202    my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
203
204
205 =head3 Predefined searches without writing a ResultSet class
206
207 Alternatively you can automatically generate a DBIx::Class::ResultSet
208 class by using the ResultSetManager component and tagging your method
209 as ResultSet:
210
211   __PACKAGE__->load_components(qw/ ResultSetManager Core /);
212
213   sub search_cds_ordered : ResultSet {
214       my ($self) = @_;
215       return $self->search(
216           {},
217           { order_by => 'name DESC' },
218       );
219   } 
220
221 Then call your method in the same way from your code:
222
223    my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
224
225 =head2 Using joins and prefetch
226
227 You can use the C<join> attribute to allow searching on, or sorting your
228 results by, one or more columns in a related table. To return all CDs matching
229 a particular artist name:
230
231   my $rs = $schema->resultset('CD')->search(
232     {
233       'artist.name' => 'Bob Marley'    
234     },
235     {
236       join => [qw/artist/], # join the artist table
237     }
238   );
239
240   # Equivalent SQL:
241   # SELECT cd.* FROM cd
242   # JOIN artist ON cd.artist = artist.id
243   # WHERE artist.name = 'Bob Marley'
244
245 If required, you can now sort on any column in the related tables by including
246 it in your C<order_by> attribute:
247
248   my $rs = $schema->resultset('CD')->search(
249     {
250       'artist.name' => 'Bob Marley'
251     },
252     {
253       join     => [qw/ artist /],
254       order_by => [qw/ artist.name /]
255     }
256   };
257
258   # Equivalent SQL:
259   # SELECT cd.* FROM cd
260   # JOIN artist ON cd.artist = artist.id
261   # WHERE artist.name = 'Bob Marley'
262   # ORDER BY artist.name
263
264 Note that the C<join> attribute should only be used when you need to search or
265 sort using columns in a related table. Joining related tables when you only
266 need columns from the main table will make performance worse!
267
268 Now let's say you want to display a list of CDs, each with the name of the
269 artist. The following will work fine:
270
271   while (my $cd = $rs->next) {
272     print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
273   }
274
275 There is a problem however. We have searched both the C<cd> and C<artist> tables
276 in our main query, but we have only returned data from the C<cd> table. To get
277 the artist name for any of the CD objects returned, L<DBIx::Class> will go back
278 to the database:
279
280   SELECT artist.* FROM artist WHERE artist.id = ?
281
282 A statement like the one above will run for each and every CD returned by our
283 main query. Five CDs, five extra queries. A hundred CDs, one hundred extra
284 queries!
285
286 Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem.
287 This allows you to fetch results from related tables in advance:
288
289   my $rs = $schema->resultset('CD')->search(
290     {
291       'artist.name' => 'Bob Marley'
292     },
293     {
294       join     => [qw/ artist /],
295       order_by => [qw/ artist.name /],
296       prefetch => [qw/ artist /] # return artist data too!
297     }
298   );
299
300   # Equivalent SQL (note SELECT from both "cd" and "artist"):
301   # SELECT cd.*, artist.* FROM cd
302   # JOIN artist ON cd.artist = artist.id
303   # WHERE artist.name = 'Bob Marley'
304   # ORDER BY artist.name
305
306 The code to print the CD list remains the same:
307
308   while (my $cd = $rs->next) {
309     print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
310   }
311
312 L<DBIx::Class> has now prefetched all matching data from the C<artist> table,
313 so no additional SQL statements are executed. You now have a much more
314 efficient query.
315
316 Note that as of L<DBIx::Class> 0.05999_01, C<prefetch> I<can> be used with
317 C<has_many> relationships.
318
319 Also note that C<prefetch> should only be used when you know you will
320 definitely use data from a related table. Pre-fetching related tables when you
321 only need columns from the main table will make performance worse!
322
323 =head3 Multi-step joins
324
325 Sometimes you want to join more than one relationship deep. In this example,
326 we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes>
327 contain a specific string:
328
329   # Relationships defined elsewhere:
330   # Artist->has_many('cds' => 'CD', 'artist');
331   # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
332
333   my $rs = $schema->resultset('Artist')->search(
334     {
335       'liner_notes.notes' => { 'like', '%some text%' },
336     },
337     {
338       join => {
339         'cds' => 'liner_notes'
340       }
341     }
342   );
343
344   # Equivalent SQL:
345   # SELECT artist.* FROM artist
346   # JOIN ( cd ON artist.id = cd.artist )
347   # JOIN ( liner_notes ON cd.id = liner_notes.cd )
348   # WHERE liner_notes.notes LIKE '%some text%'
349
350 Joins can be nested to an arbitrary level. So if we decide later that we
351 want to reduce the number of Artists returned based on who wrote the liner
352 notes:
353
354   # Relationship defined elsewhere:
355   # LinerNotes->belongs_to('author' => 'Person');
356
357   my $rs = $schema->resultset('Artist')->search(
358     {
359       'liner_notes.notes' => { 'like', '%some text%' },
360       'author.name' => 'A. Writer'
361     },
362     {
363       join => {
364         'cds' => {
365           'liner_notes' => 'author'
366         }
367       }
368     }
369   );
370
371   # Equivalent SQL:
372   # SELECT artist.* FROM artist
373   # JOIN ( cd ON artist.id = cd.artist )
374   # JOIN ( liner_notes ON cd.id = liner_notes.cd )
375   # JOIN ( author ON author.id = liner_notes.author )
376   # WHERE liner_notes.notes LIKE '%some text%'
377   # AND author.name = 'A. Writer'
378
379 =head2 Multi-step prefetch
380
381 From 0.04999_05 onwards, C<prefetch> can be nested more than one relationship
382 deep using the same syntax as a multi-step join:
383
384   my $rs = $schema->resultset('Tag')->search(
385     undef,
386     {
387       prefetch => {
388         cd => 'artist'
389       }
390     }
391   );
392
393   # Equivalent SQL:
394   # SELECT tag.*, cd.*, artist.* FROM tag
395   # JOIN cd ON tag.cd = cd.cdid
396   # JOIN artist ON cd.artist = artist.artistid
397
398 Now accessing our C<cd> and C<artist> relationships does not need additional
399 SQL statements:
400
401   my $tag = $rs->first;
402   print $tag->cd->artist->name;
403
404 =head2 Transactions
405
406 As of version 0.04001, there is improved transaction support in
407 L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>.  Here is an
408 example of the recommended way to use it:
409
410   my $genus = $schema->resultset('Genus')->find(12);
411
412   my $coderef2 = sub {
413     $genus->extinct(1);
414     $genus->update;
415   };
416
417   my $coderef1 = sub {
418     $genus->add_to_species({ name => 'troglodyte' });
419     $genus->wings(2);
420     $genus->update;
421     $schema->txn_do($coderef2); # Can have a nested transaction
422     return $genus->species;
423   };
424
425   my $rs;
426   eval {
427     $rs = $schema->txn_do($coderef1);
428   };
429
430   if ($@) {                             # Transaction failed
431     die "the sky is falling!"           #
432       if ($@ =~ /Rollback failed/);     # Rollback failed
433
434     deal_with_failed_transaction();
435   }
436
437 Nested transactions will work as expected. That is, only the outermost
438 transaction will actually issue a commit to the $dbh, and a rollback
439 at any level of any transaction will cause the entire nested
440 transaction to fail. Support for savepoints and for true nested
441 transactions (for databases that support them) will hopefully be added
442 in the future.
443
444 =head2 Many-to-many relationships
445
446 This is straightforward using L<DBIx::Class::Relationship::ManyToMany>:
447
448   package My::DB;
449   # ... set up connection ...
450
451   package My::User;
452   use base 'My::DB';
453   __PACKAGE__->table('user');
454   __PACKAGE__->add_columns(qw/id name/);
455   __PACKAGE__->set_primary_key('id');
456   __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
457   __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
458
459   package My::UserAddress;
460   use base 'My::DB';
461   __PACKAGE__->table('user_address');
462   __PACKAGE__->add_columns(qw/user address/);
463   __PACKAGE__->set_primary_key(qw/user address/);
464   __PACKAGE__->belongs_to('user' => 'My::User');
465   __PACKAGE__->belongs_to('address' => 'My::Address');
466
467   package My::Address;
468   use base 'My::DB';
469   __PACKAGE__->table('address');
470   __PACKAGE__->add_columns(qw/id street town area_code country/);
471   __PACKAGE__->set_primary_key('id');
472   __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
473   __PACKAGE__->many_to_many('users' => 'user_address', 'user');
474
475   $rs = $user->addresses(); # get all addresses for a user
476   $rs = $address->users(); # get all users for an address
477
478 =head2 Setting default values for a row
479
480 It's as simple as overriding the C<new> method.  Note the use of
481 C<next::method>.
482
483   sub new {
484     my ( $class, $attrs ) = @_;
485
486     $attrs->{foo} = 'bar' unless defined $attrs->{foo};
487
488     $class->next::method($attrs);
489   }
490
491 For more information about C<next::method>, look in the L<Class::C3> 
492 documentation. See also L<DBIx::Class::Manual::Component> for more
493 ways to write your own base classes to do this.
494
495 People looking for ways to do "triggers" with DBIx::Class are probably
496 just looking for this.
497
498 =head2 Stringification
499
500 Employ the standard stringification technique by using the C<overload>
501 module.  Replace C<foo> with the column/method of your choice.
502
503   use overload '""' => 'foo', fallback => 1;
504
505 =head2 Disconnecting cleanly
506
507 If you find yourself quitting an app with Control-C a lot during
508 development, you might like to put the following signal handler in
509 your main database class to make sure it disconnects cleanly:
510
511   $SIG{INT} = sub {
512     __PACKAGE__->storage->disconnect;
513   };
514
515 =head2 Schema import/export
516
517 This functionality requires you to have L<SQL::Translator> (also known as
518 "SQL Fairy") installed.
519
520 To create a DBIx::Class schema from an existing database:
521
522  sqlt --from DBI
523       --to DBIx::Class::File
524       --prefix "MySchema" > MySchema.pm
525
526 To create a MySQL database from an existing L<DBIx::Class> schema, convert the
527 schema to MySQL's dialect of SQL:
528
529   sqlt --from DBIx::Class --to MySQL --DBIx::Class "MySchema.pm" > Schema1.sql
530   
531 And import using the mysql client:
532
533   mysql -h "host" -D "database" -u "user" -p < Schema1.sql
534
535 =head2 Easy migration from class-based to schema-based setup
536
537 You want to start using the schema-based approach to L<DBIx::Class>
538 (see L<SchemaIntro.pod>), but have an established class-based setup with lots
539 of existing classes that you don't want to move by hand. Try this nifty script
540 instead:
541
542   use MyDB;
543   use SQL::Translator;
544   
545   my $schema = MyDB->schema_instance;
546   
547   my $translator           =  SQL::Translator->new( 
548       debug                => $debug          ||  0,
549       trace                => $trace          ||  0,
550       no_comments          => $no_comments    ||  0,
551       show_warnings        => $show_warnings  ||  0,
552       add_drop_table       => $add_drop_table ||  0,
553       validate             => $validate       ||  0,
554       parser_args          => {
555          'DBIx::Schema'    => $schema,
556                               },
557       producer_args   => {
558           'prefix'         => 'My::Schema',
559                          },
560   );
561   
562   $translator->parser('SQL::Translator::Parser::DBIx::Class');
563   $translator->producer('SQL::Translator::Producer::DBIx::Class::File');
564   
565   my $output = $translator->translate(@args) or die
566           "Error: " . $translator->error;
567   
568   print $output;
569
570 You could use L<Module::Find> to search for all subclasses in the MyDB::*
571 namespace, which is currently left as an exercise for the reader.
572
573 =head2 Schema versioning
574
575 The following example shows simplistically how you might use DBIx::Class to
576 deploy versioned schemas to your customers. The basic process is as follows:
577
578 =over 4
579
580 =item 1.
581
582 Create a DBIx::Class schema
583
584 =item 2.
585
586 Save the schema
587
588 =item 3.
589
590 Deploy to customers
591
592 =item 4.
593
594 Modify schema to change functionality
595
596 =item 5.
597
598 Deploy update to customers
599
600 =back
601
602 =head3 Create a DBIx::Class schema
603
604 This can either be done manually, or generated from an existing database as
605 described under C<Schema import/export>.
606
607 =head3 Save the schema
608
609 Use C<sqlt> to transform your schema into an SQL script suitable for your
610 customer's database. E.g. for MySQL:
611
612   sqlt --from DBIx::Class
613        --to MySQL
614        --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
615
616 If you need to target databases from multiple vendors, just generate an SQL
617 script suitable for each. To support PostgreSQL too:
618
619   sqlt --from DBIx::Class
620        --to PostgreSQL
621        --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
622
623 =head3 Deploy to customers
624
625 There are several ways you could deploy your schema. These are probably
626 beyond the scope of this recipe, but might include:
627
628 =over 4
629
630 =item 1.
631
632 Require customer to apply manually using their RDBMS.
633
634 =item 2.
635
636 Package along with your app, making database dump/schema update/tests
637 all part of your install.
638
639 =back
640
641 =head3 Modify the schema to change functionality
642
643 As your application evolves, it may be necessary to modify your schema to
644 change functionality. Once the changes are made to your schema in DBIx::Class,
645 export the modified schema as before, taking care not to overwrite the original:
646
647   sqlt --from DBIx::Class
648        --to MySQL
649        --DBIx::Class "Anything.pm" > Schema2.mysql.sql
650
651 Next, use sqlt-diff to create an SQL script that will update the customer's
652 database schema:
653
654   sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
655
656 =head3 Deploy update to customers
657
658 The schema update can be deployed to customers using the same method as before.
659
660 =head2 Setting limit dialect for SQL::Abstract::Limit
661
662 In some cases, SQL::Abstract::Limit cannot determine the dialect of the remote
663 SQL-server by looking at the database-handle. This is a common problem when
664 using the DBD::JDBC, since the DBD-driver only know that in has a Java-driver
665 available, not which JDBC-driver the Java component has loaded.
666 This specifically sets the limit_dialect to Microsoft SQL-server (Se more names
667 in SQL::Abstract::Limit -documentation.
668
669   __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
670
671 The JDBC-bridge is one way of getting access to a MSSQL-server from a platform
672 that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
673
674 =head2 Setting quotes for the generated SQL. 
675
676 If the database contains columnames with spaces and/or reserved words, the
677 SQL-query needs to be quoted. This is done using:
678
679   __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
680   __PACKAGE__->storage->sql_maker->name_sep('.');
681
682 The first sets the quotesymbols. If the quote i "symmetric" as " or '
683   
684   __PACKAGE__->storage->sql_maker->quote_char('"');
685
686 is enough. If the left quote differs form the right quote, the first 
687 notation should be used. name_sep needs to be set to allow the 
688 SQL generator to put the quotes the correct place. 
689
690 =head2 Overloading methods
691
692 L<DBIx::Class> uses the L<Class::C3> package, which provides for redispatch of 
693 method calls.  You have to use calls to C<next::method> to overload methods.  
694 More information on using L<Class::C3> with L<DBIx::Class> can be found in 
695 L<DBIx::Class::Manual::Component>.
696
697 =head3 Changing one field whenever another changes
698
699 For example, say that you have three columns, C<id>, C<number>, and 
700 C<squared>.  You would like to make changes to C<number> and have
701 C<squared> be automagically set to the value of C<number> squared.
702 You can accomplish this by overriding C<store_column>:
703
704   sub store_column {
705     my ( $self, $name, $value ) = @_;
706     if ($name eq 'number') {
707       $self->squared($value * $value);
708     }
709     $self->next::method($name, $value);
710   }
711
712 Note that the hard work is done by the call to C<next::method>, which
713 redispatches your call to store_column to the superclass(es).
714
715 =head3 Automatically creating related objects
716
717 You might have a class C<Artist> which has many C<CD>s.  Further, you
718 want to create a C<CD> object every time you insert an C<Artist> object.
719 You can accomplish this by overriding C<insert>:
720
721   sub insert {
722     my ( $class, $args_ref ) = @_;
723     my $self = $class->next::method($args_ref);
724     $self->cds->new({})->fill_from_artist($self)->insert;
725     return $self;
726   }
727
728 where C<fill_from_artist> is a method you specify in C<CD> which sets
729 values in C<CD> based on the data in the C<Artist> object you pass in.
730
731 =head2 Debugging DBIx::Class objects with Data::Dumper
732
733 L<Data::Dumper> can be a very useful tool for debugging, but sometimes it can
734 be hard to find the pertinent data in all the data it can generate.
735 Specifically, if one naively tries to use it like so,
736
737   use Data::Dumper;
738
739   my $cd = $schema->resultset('CD')->find(1);
740   print Dumper($cd);
741
742 several pages worth of data from the CD object's schema and result source will
743 be dumped to the screen. Since usually one is only interested in a few column
744 values of the object, this is not very helpful.
745
746 Luckily, it is possible to modify the data before L<Data::Dumper> outputs
747 it. Simply define a hook that L<Data::Dumper> will call on the object before
748 dumping it. For example,
749
750   package My::DB::CD;
751
752   sub _dumper_hook {
753     $_[0] = bless {
754       %{ $_[0] },
755       result_source => undef,
756     }, ref($_[0]);
757   }
758
759   [...]
760
761   use Data::Dumper;
762
763   $Data::Dumper::Freezer = '_dumper_hook';
764
765   my $cd = $schema->resultset('CD')->find(1);
766   print Dumper($cd);
767          # dumps $cd without its ResultSource
768
769 If the structure of your schema is such that there is a common base class for
770 all your table classes, simply put a method similar to C<_dumper_hook> in the
771 base class and set C<$Data::Dumper::Freezer> to its name and L<Data::Dumper>
772 will automagically clean up your data before printing it. See
773 L<Data::Dumper/EXAMPLES> for more information.
774
775 =head2 Retrieving a row object's Schema
776
777 It is possible to get a Schema object from a row object like so,
778
779   my $schema = $cd->result_source->schema;
780   my $artist_rs = $schema->resultset('Artist');
781            # for example
782
783 This can be useful when you don't want to pass around a Schema object to every
784 method.
785
786 =head2 Profiling
787
788 When you enable L<DBIx::Class::Storage::DBI>'s debugging it prints the SQL
789 executed as well as notifications of query completion and transaction
790 begin/commit.  If you'd like to profile the SQL you can subclass the
791 L<DBIx::Class::Storage::Statistics> class and write your own profiling
792 mechanism:
793
794   package My::Profiler;
795   use strict;
796
797   use base 'DBIx::Class::Storage::Statistics';
798
799   use Time::HiRes qw(time);
800
801   my $start;
802
803   sub query_start {
804     my $self = shift();
805     my $sql = shift();
806     my $params = @_;
807
808     print "Executing $sql: ".join(', ', @params)."\n";
809     $start = time();
810   }
811
812   sub query_end {
813     my $self = shift();
814     my $sql = shift();
815     my @params = @_;
816
817     printf("Execution took %0.4f seconds.\n", time() - $start);
818     $start = undef;
819   }
820
821   1;
822
823 You can then install that class as the debugging object:
824
825   __PACKAGE__->storage()->debugobj(new My::Profiler());
826   __PACKAGE__->storage()->debug(1);
827
828 A more complicated example might involve storing each execution of SQL in an
829 array:
830
831   sub query_end {
832     my $self = shift();
833     my $sql = shift();
834     my @params = @_;
835
836     my $elapsed = time() - $start;
837     push(@{ $calls{$sql} }, {
838         params => \@params,
839         elapsed => $elapsed
840     });
841   }
842
843 You could then create average, high and low execution times for an SQL
844 statement and dig down to see if certain parameters cause aberrant behavior.
845
846 =head2 Getting the value of the primary key for the last database insert
847
848 AKA getting last_insert_id
849
850 If you are using PK::Auto, this is straightforward:
851
852   my $foo = $rs->create(\%blah);
853   # do more stuff
854   my $id = $foo->id; # foo->my_primary_key_field will also work.
855
856 If you are not using autoincrementing primary keys, this will probably
857 not work, but then you already know the value of the last primary key anyway.
858
859 =cut