1DBIx::Class::Manual::CoUoskebrooCko(n3t)ributed Perl DocDuBmIexn:t:aCtliaosns::Manual::Cookbook(3)
2
3
4
6 DBIx::Class::Manual::Cookbook - Miscellaneous recipes
7
9 Paged results
10 When you expect a large number of results, you can ask DBIx::Class for
11 a paged resultset, which will fetch only a defined number of records at
12 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 return $rs->page(2); # records for page 2
25
26 You can get a Data::Page object for the resultset (suitable for use in
27 e.g. a template) using the "pager" method:
28
29 return $rs->pager();
30
31 Complex WHERE clauses
32 Sometimes you need to formulate a query using specific operators:
33
34 my @albums = $schema->resultset('Album')->search({
35 artist => { 'like', '%Lamb%' },
36 title => { 'like', '%Fear of Fours%' },
37 });
38
39 This results in something like the following "WHERE" clause:
40
41 WHERE artist LIKE ? AND title LIKE ?
42
43 And the following bind values for the placeholders: '%Lamb%', '%Fear of
44 Fours%'.
45
46 Other queries might require slightly more complex logic:
47
48 my @albums = $schema->resultset('Album')->search({
49 -or => [
50 -and => [
51 artist => { 'like', '%Smashing Pumpkins%' },
52 title => 'Siamese Dream',
53 ],
54 artist => 'Starchildren',
55 ],
56 });
57
58 This results in the following "WHERE" clause:
59
60 WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' )
61 OR artist = 'Starchildren'
62
63 For more information on generating complex queries, see "WHERE CLAUSES"
64 in SQL::Abstract.
65
66 Retrieve one and only one row from a resultset
67 Sometimes you need only the first "top" row of a resultset. While this
68 can be easily done with $rs->first, it is suboptimal, as a full blown
69 cursor for the resultset will be created and then immediately destroyed
70 after fetching the first row object. $rs->single is designed
71 specifically for this case - it will grab the first returned result
72 without even instantiating a cursor.
73
74 Before replacing all your calls to "first()" with "single()" please
75 observe the following CAVEATS:
76
77 · While single() takes a search condition just like search() does, it
78 does _not_ accept search attributes. However one can always chain a
79 single() to a search():
80
81 my $top_cd = $cd_rs->search({}, { order_by => 'rating' })->single;
82
83 · Since single() is the engine behind find(), it is designed to fetch
84 a single row per database query. Thus a warning will be issued when
85 the underlying SELECT returns more than one row. Sometimes however
86 this usage is valid: i.e. we have an arbitrary number of cd's but
87 only one of them is at the top of the charts at any given time. If
88 you know what you are doing, you can silence the warning by
89 explicitly limiting the resultset size:
90
91 my $top_cd = $cd_rs->search ({}, { order_by => 'rating', rows => 1 })->single;
92
93 Arbitrary SQL through a custom ResultSource
94 Sometimes you have to run arbitrary SQL because your query is too
95 complex (e.g. it contains Unions, Sub-Selects, Stored Procedures, etc.)
96 or has to be optimized for your database in a special way, but you
97 still want to get the results as a DBIx::Class::ResultSet.
98
99 This is accomplished by defining a ResultSource::View for your query,
100 almost like you would define a regular ResultSource.
101
102 package My::Schema::Result::UserFriendsComplex;
103 use strict;
104 use warnings;
105 use base qw/DBIx::Class::Core/;
106
107 __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
108
109 # ->table, ->add_columns, etc.
110
111 # do not attempt to deploy() this view
112 __PACKAGE__->result_source_instance->is_virtual(1);
113
114 __PACKAGE__->result_source_instance->view_definition(q[
115 SELECT u.* FROM user u
116 INNER JOIN user_friends f ON u.id = f.user_id
117 WHERE f.friend_user_id = ?
118 UNION
119 SELECT u.* FROM user u
120 INNER JOIN user_friends f ON u.id = f.friend_user_id
121 WHERE f.user_id = ?
122 ]);
123
124 Next, you can execute your complex query using bind parameters like
125 this:
126
127 my $friends = $schema->resultset( 'UserFriendsComplex' )->search( {},
128 {
129 bind => [ 12345, 12345 ]
130 }
131 );
132
133 ... and you'll get back a perfect DBIx::Class::ResultSet (except, of
134 course, that you cannot modify the rows it contains, e.g. cannot call
135 "update", "delete", ... on it).
136
137 Note that you cannot have bind parameters unless is_virtual is set to
138 true.
139
140 · NOTE
141
142 If you're using the old deprecated "$rsrc_instance->name(\'( SELECT
143 ...')" method for custom SQL execution, you are highly encouraged
144 to update your code to use a virtual view as above. If you do not
145 want to change your code, and just want to suppress the deprecation
146 warning when you call "deploy" in DBIx::Class::Schema, add this
147 line to your source definition, so that "deploy" will exclude this
148 "table":
149
150 sub sqlt_deploy_hook { $_[1]->schema->drop_table ($_[1]) }
151
152 Using specific columns
153 When you only want specific columns from a table, you can use "columns"
154 to specify which ones you need. This is useful to avoid loading columns
155 with large amounts of data that you aren't about to use anyway:
156
157 my $rs = $schema->resultset('Artist')->search(
158 undef,
159 {
160 columns => [qw/ name /]
161 }
162 );
163
164 # Equivalent SQL:
165 # SELECT artist.name FROM artist
166
167 This is a shortcut for "select" and "as", see below. "columns" cannot
168 be used together with "select" and "as".
169
170 Using database functions or stored procedures
171 The combination of "select" and "as" can be used to return the result
172 of a database function or stored procedure as a column value. You use
173 "select" to specify the source for your column value (e.g. a column
174 name, function, or stored procedure name). You then use "as" to set the
175 column name you will use to access the returned value:
176
177 my $rs = $schema->resultset('Artist')->search(
178 {},
179 {
180 select => [ 'name', { LENGTH => 'name' } ],
181 as => [qw/ name name_length /],
182 }
183 );
184
185 # Equivalent SQL:
186 # SELECT name name, LENGTH( name )
187 # FROM artist
188
189 Note that the "as" attribute has absolutely nothing to do with the SQL
190 syntax " SELECT foo AS bar " (see the documentation in "ATTRIBUTES" in
191 DBIx::Class::ResultSet). You can control the "AS" part of the generated
192 SQL via the "-as" field attribute as follows:
193
194 my $rs = $schema->resultset('Artist')->search(
195 {},
196 {
197 join => 'cds',
198 distinct => 1,
199 '+select' => [ { count => 'cds.cdid', -as => 'amount_of_cds' } ],
200 '+as' => [qw/num_cds/],
201 order_by => { -desc => 'amount_of_cds' },
202 }
203 );
204
205 # Equivalent SQL
206 # SELECT me.artistid, me.name, me.rank, me.charfield, COUNT( cds.cdid ) AS amount_of_cds
207 # FROM artist me LEFT JOIN cd cds ON cds.artist = me.artistid
208 # GROUP BY me.artistid, me.name, me.rank, me.charfield
209 # ORDER BY amount_of_cds DESC
210
211 If your alias exists as a column in your base class (i.e. it was added
212 with add_columns), you just access it as normal. Our "Artist" class has
213 a "name" column, so we just use the "name" accessor:
214
215 my $artist = $rs->first();
216 my $name = $artist->name();
217
218 If on the other hand the alias does not correspond to an existing
219 column, you have to fetch the value using the "get_column" accessor:
220
221 my $name_length = $artist->get_column('name_length');
222
223 If you don't like using "get_column", you can always create an accessor
224 for any of your aliases using either of these:
225
226 # Define accessor manually:
227 sub name_length { shift->get_column('name_length'); }
228
229 # Or use DBIx::Class::AccessorGroup:
230 __PACKAGE__->mk_group_accessors('column' => 'name_length');
231
232 See also "Using SQL functions on the left hand side of a comparison".
233
234 SELECT DISTINCT with multiple columns
235 my $rs = $schema->resultset('Artist')->search(
236 {},
237 {
238 columns => [ qw/artist_id name rank/ ],
239 distinct => 1
240 }
241 );
242
243 my $rs = $schema->resultset('Artist')->search(
244 {},
245 {
246 columns => [ qw/artist_id name rank/ ],
247 group_by => [ qw/artist_id name rank/ ],
248 }
249 );
250
251 # Equivalent SQL:
252 # SELECT me.artist_id, me.name, me.rank
253 # FROM artist me
254 # GROUP BY artist_id, name, rank
255
256 SELECT COUNT(DISTINCT colname)
257 my $rs = $schema->resultset('Artist')->search(
258 {},
259 {
260 columns => [ qw/name/ ],
261 distinct => 1
262 }
263 );
264
265 my $rs = $schema->resultset('Artist')->search(
266 {},
267 {
268 columns => [ qw/name/ ],
269 group_by => [ qw/name/ ],
270 }
271 );
272
273 my $count = $rs->count;
274
275 # Equivalent SQL:
276 # SELECT COUNT( * ) FROM (SELECT me.name FROM artist me GROUP BY me.name) count_subq:
277
278 Grouping results
279 DBIx::Class supports "GROUP BY" as follows:
280
281 my $rs = $schema->resultset('Artist')->search(
282 {},
283 {
284 join => [qw/ cds /],
285 select => [ 'name', { count => 'cds.id' } ],
286 as => [qw/ name cd_count /],
287 group_by => [qw/ name /]
288 }
289 );
290
291 # Equivalent SQL:
292 # SELECT name, COUNT( cd.id ) FROM artist
293 # LEFT JOIN cd ON artist.id = cd.artist
294 # GROUP BY name
295
296 Please see "ATTRIBUTES" in DBIx::Class::ResultSet documentation if you
297 are in any way unsure about the use of the attributes above (" join ",
298 " select ", " as " and " group_by ").
299
300 Subqueries
301 You can write subqueries relatively easily in DBIC.
302
303 my $inside_rs = $schema->resultset('Artist')->search({
304 name => [ 'Billy Joel', 'Brittany Spears' ],
305 });
306
307 my $rs = $schema->resultset('CD')->search({
308 artist_id => { 'IN' => $inside_rs->get_column('id')->as_query },
309 });
310
311 The usual operators ( =, !=, IN, NOT IN, etc.) are supported.
312
313 NOTE: You have to explicitly use '=' when doing an equality comparison.
314 The following will not work:
315
316 my $rs = $schema->resultset('CD')->search({
317 artist_id => $inside_rs->get_column('id')->as_query, # does NOT work
318 });
319
320 Support
321
322 Subqueries are supported in the where clause (first hashref), and in
323 the from, select, and +select attributes.
324
325 Correlated subqueries
326
327 my $cdrs = $schema->resultset('CD');
328 my $rs = $cdrs->search({
329 year => {
330 '=' => $cdrs->search(
331 { artist_id => { '=' => \'me.artist_id' } },
332 { alias => 'inner' }
333 )->get_column('year')->max_rs->as_query,
334 },
335 });
336
337 That creates the following SQL:
338
339 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
340 FROM cd me
341 WHERE year = (
342 SELECT MAX(inner.year)
343 FROM cd inner
344 WHERE artist_id = me.artist_id
345 )
346
347 Predefined searches
348 You can write your own DBIx::Class::ResultSet class by inheriting from
349 it and defining often used searches as methods:
350
351 package My::DBIC::ResultSet::CD;
352 use strict;
353 use warnings;
354 use base 'DBIx::Class::ResultSet';
355
356 sub search_cds_ordered {
357 my ($self) = @_;
358
359 return $self->search(
360 {},
361 { order_by => 'name DESC' },
362 );
363 }
364
365 1;
366
367 If you're using "load_namespaces" in DBIx::Class::Schema, simply place
368 the file into the "ResultSet" directory next to your "Result"
369 directory, and it will be automatically loaded.
370
371 If however you are still using "load_classes" in DBIx::Class::Schema,
372 first tell DBIx::Class to create an instance of the ResultSet class for
373 you, in your My::DBIC::Schema::CD class:
374
375 # class definition as normal
376 use base 'DBIx::Class::Core';
377 __PACKAGE__->table('cd');
378
379 # tell DBIC to use the custom ResultSet class
380 __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
381
382 Note that "resultset_class" must be called after "load_components" and
383 "table", or you will get errors about missing methods.
384
385 Then call your new method in your code:
386
387 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
388
389 Using SQL functions on the left hand side of a comparison
390 Using SQL functions on the left hand side of a comparison is generally
391 not a good idea since it requires a scan of the entire table. (Unless
392 your RDBMS supports indexes on expressions - including return values of
393 functions - and you create an index on the return value of the function
394 in question.) However, it can be accomplished with "DBIx::Class" when
395 necessary.
396
397 If you do not have quoting on, simply include the function in your
398 search specification as you would any column:
399
400 $rs->search({ 'YEAR(date_of_birth)' => 1979 });
401
402 With quoting on, or for a more portable solution, use literal SQL
403 values with placeholders:
404
405 $rs->search(\[ 'YEAR(date_of_birth) = ?', [ plain_value => 1979 ] ]);
406
407 # Equivalent SQL:
408 # SELECT * FROM employee WHERE YEAR(date_of_birth) = ?
409
410 $rs->search({
411 name => 'Bob',
412 -nest => \[ 'YEAR(date_of_birth) = ?', [ plain_value => 1979 ] ],
413 });
414
415 # Equivalent SQL:
416 # SELECT * FROM employee WHERE name = ? AND YEAR(date_of_birth) = ?
417
418 Note: the "plain_value" string in the "[ plain_value => 1979 ]" part
419 should be either the same as the name of the column (do this if the
420 type of the return value of the function is the same as the type of the
421 column) or otherwise it's essentially a dummy string currently (use
422 "plain_value" as a habit). It is used by DBIx::Class to handle special
423 column types.
424
425 See also "Literal SQL with placeholders and bind values (subqueries)"
426 in SQL::Abstract.
427
429 Using joins and prefetch
430 You can use the "join" attribute to allow searching on, or sorting your
431 results by, one or more columns in a related table.
432
433 This requires that you have defined the DBIx::Class::Relationship. For
434 example :
435
436 My::Schema::CD->has_many( artists => 'My::Schema::Artist', 'artist_id');
437
438 To return all CDs matching a particular artist name, you specify the
439 name of the relationship ('artists'):
440
441 my $rs = $schema->resultset('CD')->search(
442 {
443 'artists.name' => 'Bob Marley'
444 },
445 {
446 join => 'artists', # join the artist table
447 }
448 );
449
450 # Equivalent SQL:
451 # SELECT cd.* FROM cd
452 # JOIN artist ON cd.artist = artist.id
453 # WHERE artist.name = 'Bob Marley'
454
455 In that example both the join, and the condition use the relationship
456 name rather than the table name (see DBIx::Class::Manual::Joining for
457 more details on aliasing ).
458
459 If required, you can now sort on any column in the related tables by
460 including it in your "order_by" attribute, (again using the aliased
461 relation name rather than table name) :
462
463 my $rs = $schema->resultset('CD')->search(
464 {
465 'artists.name' => 'Bob Marley'
466 },
467 {
468 join => 'artists',
469 order_by => [qw/ artists.name /]
470 }
471 );
472
473 # Equivalent SQL:
474 # SELECT cd.* FROM cd
475 # JOIN artist ON cd.artist = artist.id
476 # WHERE artist.name = 'Bob Marley'
477 # ORDER BY artist.name
478
479 Note that the "join" attribute should only be used when you need to
480 search or sort using columns in a related table. Joining related tables
481 when you only need columns from the main table will make performance
482 worse!
483
484 Now let's say you want to display a list of CDs, each with the name of
485 the artist. The following will work fine:
486
487 while (my $cd = $rs->next) {
488 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
489 }
490
491 There is a problem however. We have searched both the "cd" and "artist"
492 tables in our main query, but we have only returned data from the "cd"
493 table. To get the artist name for any of the CD objects returned,
494 DBIx::Class will go back to the database:
495
496 SELECT artist.* FROM artist WHERE artist.id = ?
497
498 A statement like the one above will run for each and every CD returned
499 by our main query. Five CDs, five extra queries. A hundred CDs, one
500 hundred extra queries!
501
502 Thankfully, DBIx::Class has a "prefetch" attribute to solve this
503 problem. This allows you to fetch results from related tables in
504 advance:
505
506 my $rs = $schema->resultset('CD')->search(
507 {
508 'artists.name' => 'Bob Marley'
509 },
510 {
511 join => 'artists',
512 order_by => [qw/ artists.name /],
513 prefetch => 'artists' # return artist data too!
514 }
515 );
516
517 # Equivalent SQL (note SELECT from both "cd" and "artist"):
518 # SELECT cd.*, artist.* FROM cd
519 # JOIN artist ON cd.artist = artist.id
520 # WHERE artist.name = 'Bob Marley'
521 # ORDER BY artist.name
522
523 The code to print the CD list remains the same:
524
525 while (my $cd = $rs->next) {
526 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
527 }
528
529 DBIx::Class has now prefetched all matching data from the "artist"
530 table, so no additional SQL statements are executed. You now have a
531 much more efficient query.
532
533 Also note that "prefetch" should only be used when you know you will
534 definitely use data from a related table. Pre-fetching related tables
535 when you only need columns from the main table will make performance
536 worse!
537
538 Multiple joins
539 In the examples above, the "join" attribute was a scalar. If you pass
540 an array reference instead, you can join to multiple tables. In this
541 example, we want to limit the search further, using "LinerNotes":
542
543 # Relationships defined elsewhere:
544 # CD->belongs_to('artist' => 'Artist');
545 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
546 my $rs = $schema->resultset('CD')->search(
547 {
548 'artist.name' => 'Bob Marley'
549 'liner_notes.notes' => { 'like', '%some text%' },
550 },
551 {
552 join => [qw/ artist liner_notes /],
553 order_by => [qw/ artist.name /],
554 }
555 );
556
557 # Equivalent SQL:
558 # SELECT cd.*, artist.*, liner_notes.* FROM cd
559 # JOIN artist ON cd.artist = artist.id
560 # JOIN liner_notes ON cd.id = liner_notes.cd
561 # WHERE artist.name = 'Bob Marley'
562 # ORDER BY artist.name
563
564 Multi-step joins
565 Sometimes you want to join more than one relationship deep. In this
566 example, we want to find all "Artist" objects who have "CD"s whose
567 "LinerNotes" contain a specific string:
568
569 # Relationships defined elsewhere:
570 # Artist->has_many('cds' => 'CD', 'artist');
571 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
572
573 my $rs = $schema->resultset('Artist')->search(
574 {
575 'liner_notes.notes' => { 'like', '%some text%' },
576 },
577 {
578 join => {
579 'cds' => 'liner_notes'
580 }
581 }
582 );
583
584 # Equivalent SQL:
585 # SELECT artist.* FROM artist
586 # LEFT JOIN cd ON artist.id = cd.artist
587 # LEFT JOIN liner_notes ON cd.id = liner_notes.cd
588 # WHERE liner_notes.notes LIKE '%some text%'
589
590 Joins can be nested to an arbitrary level. So if we decide later that
591 we want to reduce the number of Artists returned based on who wrote the
592 liner notes:
593
594 # Relationship defined elsewhere:
595 # LinerNotes->belongs_to('author' => 'Person');
596
597 my $rs = $schema->resultset('Artist')->search(
598 {
599 'liner_notes.notes' => { 'like', '%some text%' },
600 'author.name' => 'A. Writer'
601 },
602 {
603 join => {
604 'cds' => {
605 'liner_notes' => 'author'
606 }
607 }
608 }
609 );
610
611 # Equivalent SQL:
612 # SELECT artist.* FROM artist
613 # LEFT JOIN cd ON artist.id = cd.artist
614 # LEFT JOIN liner_notes ON cd.id = liner_notes.cd
615 # LEFT JOIN author ON author.id = liner_notes.author
616 # WHERE liner_notes.notes LIKE '%some text%'
617 # AND author.name = 'A. Writer'
618
619 Multi-step and multiple joins
620 With various combinations of array and hash references, you can join
621 tables in any combination you desire. For example, to join Artist to
622 CD and Concert, and join CD to LinerNotes:
623
624 # Relationships defined elsewhere:
625 # Artist->has_many('concerts' => 'Concert', 'artist');
626
627 my $rs = $schema->resultset('Artist')->search(
628 { },
629 {
630 join => [
631 {
632 cds => 'liner_notes'
633 },
634 'concerts'
635 ],
636 }
637 );
638
639 # Equivalent SQL:
640 # SELECT artist.* FROM artist
641 # LEFT JOIN cd ON artist.id = cd.artist
642 # LEFT JOIN liner_notes ON cd.id = liner_notes.cd
643 # LEFT JOIN concert ON artist.id = concert.artist
644
645 Multi-step prefetch
646 "prefetch" can be nested more than one relationship deep using the same
647 syntax as a multi-step join:
648
649 my $rs = $schema->resultset('Tag')->search(
650 {},
651 {
652 prefetch => {
653 cd => 'artist'
654 }
655 }
656 );
657
658 # Equivalent SQL:
659 # SELECT tag.*, cd.*, artist.* FROM tag
660 # JOIN cd ON tag.cd = cd.id
661 # JOIN artist ON cd.artist = artist.id
662
663 Now accessing our "cd" and "artist" relationships does not need
664 additional SQL statements:
665
666 my $tag = $rs->first;
667 print $tag->cd->artist->name;
668
670 Retrieving a row object's Schema
671 It is possible to get a Schema object from a row object like so:
672
673 my $schema = $cd->result_source->schema;
674 # use the schema as normal:
675 my $artist_rs = $schema->resultset('Artist');
676
677 This can be useful when you don't want to pass around a Schema object
678 to every method.
679
680 Getting the value of the primary key for the last database insert
681 AKA getting last_insert_id
682
683 Thanks to the core component PK::Auto, this is straightforward:
684
685 my $foo = $rs->create(\%blah);
686 # do more stuff
687 my $id = $foo->id; # foo->my_primary_key_field will also work.
688
689 If you are not using autoincrementing primary keys, this will probably
690 not work, but then you already know the value of the last primary key
691 anyway.
692
693 Stringification
694 Employ the standard stringification technique by using the overload
695 module.
696
697 To make an object stringify itself as a single column, use something
698 like this (replace "name" with the column/method of your choice):
699
700 use overload '""' => sub { shift->name}, fallback => 1;
701
702 For more complex stringification, you can use an anonymous subroutine:
703
704 use overload '""' => sub { $_[0]->name . ", " .
705 $_[0]->address }, fallback => 1;
706
707 Stringification Example
708
709 Suppose we have two tables: "Product" and "Category". The table
710 specifications are:
711
712 Product(id, Description, category)
713 Category(id, Description)
714
715 "category" is a foreign key into the Category table.
716
717 If you have a Product object $obj and write something like
718
719 print $obj->category
720
721 things will not work as expected.
722
723 To obtain, for example, the category description, you should add this
724 method to the class defining the Category table:
725
726 use overload "" => sub {
727 my $self = shift;
728
729 return $self->Description;
730 }, fallback => 1;
731
732 Want to know if find_or_create found or created a row?
733 Just use "find_or_new" instead, then check "in_storage":
734
735 my $obj = $rs->find_or_new({ blah => 'blarg' });
736 unless ($obj->in_storage) {
737 $obj->insert;
738 # do whatever else you wanted if it was a new row
739 }
740
741 Static sub-classing DBIx::Class result classes
742 AKA adding additional relationships/methods/etc. to a model for a
743 specific usage of the (shared) model.
744
745 Schema definition
746
747 package My::App::Schema;
748
749 use base 'DBIx::Class::Schema';
750
751 # load subclassed classes from My::App::Schema::Result/ResultSet
752 __PACKAGE__->load_namespaces;
753
754 # load classes from shared model
755 load_classes({
756 'My::Shared::Model::Result' => [qw/
757 Foo
758 Bar
759 /]});
760
761 1;
762
763 Result-Subclass definition
764
765 package My::App::Schema::Result::Baz;
766
767 use strict;
768 use warnings;
769 use base 'My::Shared::Model::Result::Baz';
770
771 # WARNING: Make sure you call table() again in your subclass,
772 # otherwise DBIx::Class::ResultSourceProxy::Table will not be called
773 # and the class name is not correctly registered as a source
774 __PACKAGE__->table('baz');
775
776 sub additional_method {
777 return "I'm an additional method only needed by this app";
778 }
779
780 1;
781
782 Dynamic Sub-classing DBIx::Class proxy classes
783 AKA multi-class object inflation from one table
784
785 DBIx::Class classes are proxy classes, therefore some different
786 techniques need to be employed for more than basic subclassing. In
787 this example we have a single user table that carries a boolean bit for
788 admin. We would like like to give the admin users objects
789 (DBIx::Class::Row) the same methods as a regular user but also special
790 admin only methods. It doesn't make sense to create two separate
791 proxy-class files for this. We would be copying all the user methods
792 into the Admin class. There is a cleaner way to accomplish this.
793
794 Overriding the "inflate_result" method within the User proxy-class
795 gives us the effect we want. This method is called by
796 DBIx::Class::ResultSet when inflating a result from storage. So we
797 grab the object being returned, inspect the values we are looking for,
798 bless it if it's an admin object, and then return it. See the example
799 below:
800
801 Schema Definition
802
803 package My::Schema;
804
805 use base qw/DBIx::Class::Schema/;
806
807 __PACKAGE__->load_namespaces;
808
809 1;
810
811 Proxy-Class definitions
812
813 package My::Schema::Result::User;
814
815 use strict;
816 use warnings;
817 use base qw/DBIx::Class::Core/;
818
819 ### Define what our admin class is, for ensure_class_loaded()
820 my $admin_class = __PACKAGE__ . '::Admin';
821
822 __PACKAGE__->table('users');
823
824 __PACKAGE__->add_columns(qw/user_id email password
825 firstname lastname active
826 admin/);
827
828 __PACKAGE__->set_primary_key('user_id');
829
830 sub inflate_result {
831 my $self = shift;
832 my $ret = $self->next::method(@_);
833 if( $ret->admin ) {### If this is an admin, rebless for extra functions
834 $self->ensure_class_loaded( $admin_class );
835 bless $ret, $admin_class;
836 }
837 return $ret;
838 }
839
840 sub hello {
841 print "I am a regular user.\n";
842 return ;
843 }
844
845 1;
846
847
848 package My::Schema::Result::User::Admin;
849
850 use strict;
851 use warnings;
852 use base qw/My::Schema::Result::User/;
853
854 # This line is important
855 __PACKAGE__->table('users');
856
857 sub hello
858 {
859 print "I am an admin.\n";
860 return;
861 }
862
863 sub do_admin_stuff
864 {
865 print "I am doing admin stuff\n";
866 return ;
867 }
868
869 1;
870
871 Test File test.pl
872
873 use warnings;
874 use strict;
875 use My::Schema;
876
877 my $user_data = { email => 'someguy@place.com',
878 password => 'pass1',
879 admin => 0 };
880
881 my $admin_data = { email => 'someadmin@adminplace.com',
882 password => 'pass2',
883 admin => 1 };
884
885 my $schema = My::Schema->connection('dbi:Pg:dbname=test');
886
887 $schema->resultset('User')->create( $user_data );
888 $schema->resultset('User')->create( $admin_data );
889
890 ### Now we search for them
891 my $user = $schema->resultset('User')->single( $user_data );
892 my $admin = $schema->resultset('User')->single( $admin_data );
893
894 print ref $user, "\n";
895 print ref $admin, "\n";
896
897 print $user->password , "\n"; # pass1
898 print $admin->password , "\n";# pass2; inherited from User
899 print $user->hello , "\n";# I am a regular user.
900 print $admin->hello, "\n";# I am an admin.
901
902 ### The statement below will NOT print
903 print "I can do admin stuff\n" if $user->can('do_admin_stuff');
904 ### The statement below will print
905 print "I can do admin stuff\n" if $admin->can('do_admin_stuff');
906
907 Alternatively you can use DBIx::Class::DynamicSubclass that implements
908 exactly the above functionality.
909
910 Skip row object creation for faster results
911 DBIx::Class is not built for speed, it's built for convenience and ease
912 of use, but sometimes you just need to get the data, and skip the fancy
913 objects.
914
915 To do this simply use DBIx::Class::ResultClass::HashRefInflator.
916
917 my $rs = $schema->resultset('CD');
918
919 $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
920
921 my $hash_ref = $rs->find(1);
922
923 Wasn't that easy?
924
925 Beware, changing the Result class using "result_class" in
926 DBIx::Class::ResultSet will replace any existing class completely
927 including any special components loaded using load_components, eg
928 DBIx::Class::InflateColumn::DateTime.
929
930 Get raw data for blindingly fast results
931 If the HashRefInflator solution above is not fast enough for you, you
932 can use a DBIx::Class to return values exactly as they come out of the
933 database with none of the convenience methods wrapped round them.
934
935 This is used like so:
936
937 my $cursor = $rs->cursor
938 while (my @vals = $cursor->next) {
939 # use $val[0..n] here
940 }
941
942 You will need to map the array offsets to particular columns (you can
943 use the "select" in DBIx::Class::ResultSet attribute of "search" in
944 DBIx::Class::ResultSet to force ordering).
945
947 Getting Schema from a ResultSet
948 To get the DBIx::Class::Schema object from a ResultSet, do the
949 following:
950
951 $rs->result_source->schema
952
953 Getting Columns Of Data
954 AKA Aggregating Data
955
956 If you want to find the sum of a particular column there are several
957 ways, the obvious one is to use search:
958
959 my $rs = $schema->resultset('Items')->search(
960 {},
961 {
962 select => [ { sum => 'Cost' } ],
963 as => [ 'total_cost' ], # remember this 'as' is for DBIx::Class::ResultSet not SQL
964 }
965 );
966 my $tc = $rs->first->get_column('total_cost');
967
968 Or, you can use the DBIx::Class::ResultSetColumn, which gets returned
969 when you ask the "ResultSet" for a column using "get_column":
970
971 my $cost = $schema->resultset('Items')->get_column('Cost');
972 my $tc = $cost->sum;
973
974 With this you can also do:
975
976 my $minvalue = $cost->min;
977 my $maxvalue = $cost->max;
978
979 Or just iterate through the values of this column only:
980
981 while ( my $c = $cost->next ) {
982 print $c;
983 }
984
985 foreach my $c ($cost->all) {
986 print $c;
987 }
988
989 "ResultSetColumn" only has a limited number of built-in functions. If
990 you need one that it doesn't have, then you can use the "func" method
991 instead:
992
993 my $avg = $cost->func('AVERAGE');
994
995 This will cause the following SQL statement to be run:
996
997 SELECT AVERAGE(Cost) FROM Items me
998
999 Which will of course only work if your database supports this function.
1000 See DBIx::Class::ResultSetColumn for more documentation.
1001
1002 Creating a result set from a set of rows
1003 Sometimes you have a (set of) row objects that you want to put into a
1004 resultset without the need to hit the DB again. You can do that by
1005 using the set_cache method:
1006
1007 my @uploadable_groups;
1008 while (my $group = $groups->next) {
1009 if ($group->can_upload($self)) {
1010 push @uploadable_groups, $group;
1011 }
1012 }
1013 my $new_rs = $self->result_source->resultset;
1014 $new_rs->set_cache(\@uploadable_groups);
1015 return $new_rs;
1016
1018 Create a new row in a related table
1019 my $author = $book->create_related('author', { name => 'Fred'});
1020
1021 Search in a related table
1022 Only searches for books named 'Titanic' by the author in $author.
1023
1024 my $books_rs = $author->search_related('books', { name => 'Titanic' });
1025
1026 Delete data in a related table
1027 Deletes only the book named Titanic by the author in $author.
1028
1029 $author->delete_related('books', { name => 'Titanic' });
1030
1031 Ordering a relationship result set
1032 If you always want a relation to be ordered, you can specify this when
1033 you create the relationship.
1034
1035 To order "$book->pages" by descending page_number, create the relation
1036 as follows:
1037
1038 __PACKAGE__->has_many('pages' => 'Page', 'book', { order_by => { -desc => 'page_number'} } );
1039
1040 Filtering a relationship result set
1041 If you want to get a filtered result set, you can just add add to $attr
1042 as follows:
1043
1044 __PACKAGE__->has_many('pages' => 'Page', 'book', { where => { scrap => 0 } } );
1045
1046 Many-to-many relationships
1047 This is straightforward using ManyToMany:
1048
1049 package My::User;
1050 use base 'DBIx::Class::Core';
1051 __PACKAGE__->table('user');
1052 __PACKAGE__->add_columns(qw/id name/);
1053 __PACKAGE__->set_primary_key('id');
1054 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
1055 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
1056
1057 package My::UserAddress;
1058 use base 'DBIx::Class::Core';
1059 __PACKAGE__->table('user_address');
1060 __PACKAGE__->add_columns(qw/user address/);
1061 __PACKAGE__->set_primary_key(qw/user address/);
1062 __PACKAGE__->belongs_to('user' => 'My::User');
1063 __PACKAGE__->belongs_to('address' => 'My::Address');
1064
1065 package My::Address;
1066 use base 'DBIx::Class::Core';
1067 __PACKAGE__->table('address');
1068 __PACKAGE__->add_columns(qw/id street town area_code country/);
1069 __PACKAGE__->set_primary_key('id');
1070 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
1071 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
1072
1073 $rs = $user->addresses(); # get all addresses for a user
1074 $rs = $address->users(); # get all users for an address
1075
1076 my $address = $user->add_to_addresses( # returns a My::Address instance,
1077 # NOT a My::UserAddress instance!
1078 {
1079 country => 'United Kingdom',
1080 area_code => 'XYZ',
1081 town => 'London',
1082 street => 'Sesame',
1083 }
1084 );
1085
1086 Relationships across DB schemas
1087 Mapping relationships across DB schemas is easy as long as the schemas
1088 themselves are all accessible via the same DBI connection. In most
1089 cases, this means that they are on the same database host as each other
1090 and your connecting database user has the proper permissions to them.
1091
1092 To accomplish this one only needs to specify the DB schema name in the
1093 table declaration, like so...
1094
1095 package MyDatabase::Main::Artist;
1096 use base qw/DBIx::Class::Core/;
1097
1098 __PACKAGE__->table('database1.artist'); # will use "database1.artist" in FROM clause
1099
1100 __PACKAGE__->add_columns(qw/ artist_id name /);
1101 __PACKAGE__->set_primary_key('artist_id');
1102 __PACKAGE__->has_many('cds' => 'MyDatabase::Main::Cd');
1103
1104 1;
1105
1106 Whatever string you specify there will be used to build the "FROM"
1107 clause in SQL queries.
1108
1109 The big drawback to this is you now have DB schema names hardcoded in
1110 your class files. This becomes especially troublesome if you have
1111 multiple instances of your application to support a change lifecycle
1112 (e.g. DEV, TEST, PROD) and the DB schemas are named based on the
1113 environment (e.g. database1_dev).
1114
1115 However, one can dynamically "map" to the proper DB schema by
1116 overriding the connection method in your Schema class and building a
1117 renaming facility, like so:
1118
1119 package MyDatabase::Schema;
1120 use Moose;
1121
1122 extends 'DBIx::Class::Schema';
1123
1124 around connection => sub {
1125 my ( $inner, $self, $dsn, $username, $pass, $attr ) = ( shift, @_ );
1126
1127 my $postfix = delete $attr->{schema_name_postfix};
1128
1129 $inner->(@_);
1130
1131 if ( $postfix ) {
1132 $self->append_db_name($postfix);
1133 }
1134 };
1135
1136 sub append_db_name {
1137 my ( $self, $postfix ) = @_;
1138
1139 my @sources_with_db
1140 = grep
1141 { $_->name =~ /^\w+\./mx }
1142 map
1143 { $self->source($_) }
1144 $self->sources;
1145
1146 foreach my $source (@sources_with_db) {
1147 my $name = $source->name;
1148 $name =~ s{^(\w+)\.}{${1}${postfix}\.}mx;
1149
1150 $source->name($name);
1151 }
1152 }
1153
1154 1;
1155
1156 By overridding the connection method and extracting a custom option
1157 from the provided \%attr hashref one can then simply iterate over all
1158 the Schema's ResultSources, renaming them as needed.
1159
1160 To use this facility, simply add or modify the \%attr hashref that is
1161 passed to connection, as follows:
1162
1163 my $schema
1164 = MyDatabase::Schema->connect(
1165 $dsn,
1166 $user,
1167 $pass,
1168 {
1169 schema_name_postfix => '_dev'
1170 # ... Other options as desired ...
1171 })
1172
1173 Obviously, one could accomplish even more advanced mapping via a hash
1174 map or a callback routine.
1175
1177 As of version 0.04001, there is improved transaction support in
1178 DBIx::Class::Storage and DBIx::Class::Schema. Here is an example of
1179 the recommended way to use it:
1180
1181 my $genus = $schema->resultset('Genus')->find(12);
1182
1183 my $coderef2 = sub {
1184 $genus->extinct(1);
1185 $genus->update;
1186 };
1187
1188 my $coderef1 = sub {
1189 $genus->add_to_species({ name => 'troglodyte' });
1190 $genus->wings(2);
1191 $genus->update;
1192 $schema->txn_do($coderef2); # Can have a nested transaction. Only the outer will actualy commit
1193 return $genus->species;
1194 };
1195
1196 my $rs;
1197 eval {
1198 $rs = $schema->txn_do($coderef1);
1199 };
1200
1201 if ($@) { # Transaction failed
1202 die "the sky is falling!" #
1203 if ($@ =~ /Rollback failed/); # Rollback failed
1204
1205 deal_with_failed_transaction();
1206 }
1207
1208 Nested transactions will work as expected. That is, only the outermost
1209 transaction will actually issue a commit to the $dbh, and a rollback at
1210 any level of any transaction will cause the entire nested transaction
1211 to fail.
1212
1213 Nested transactions and auto-savepoints
1214 If savepoints are supported by your RDBMS, it is possible to achieve
1215 true nested transactions with minimal effort. To enable auto-savepoints
1216 via nested transactions, supply the "auto_savepoint = 1" connection
1217 attribute.
1218
1219 Here is an example of true nested transactions. In the example, we
1220 start a big task which will create several rows. Generation of data for
1221 each row is a fragile operation and might fail. If we fail creating
1222 something, depending on the type of failure, we want to abort the whole
1223 task, or only skip the failed row.
1224
1225 my $schema = MySchema->connect("dbi:Pg:dbname=my_db");
1226
1227 # Start a transaction. Every database change from here on will only be
1228 # committed into the database if the eval block succeeds.
1229 eval {
1230 $schema->txn_do(sub {
1231 # SQL: BEGIN WORK;
1232
1233 my $job = $schema->resultset('Job')->create({ name=> 'big job' });
1234 # SQL: INSERT INTO job ( name) VALUES ( 'big job' );
1235
1236 for (1..10) {
1237
1238 # Start a nested transaction, which in fact sets a savepoint.
1239 eval {
1240 $schema->txn_do(sub {
1241 # SQL: SAVEPOINT savepoint_0;
1242
1243 my $thing = $schema->resultset('Thing')->create({ job=>$job->id });
1244 # SQL: INSERT INTO thing ( job) VALUES ( 1 );
1245
1246 if (rand > 0.8) {
1247 # This will generate an error, thus setting $@
1248
1249 $thing->update({force_fail=>'foo'});
1250 # SQL: UPDATE thing SET force_fail = 'foo'
1251 # WHERE ( id = 42 );
1252 }
1253 });
1254 };
1255 if ($@) {
1256 # SQL: ROLLBACK TO SAVEPOINT savepoint_0;
1257
1258 # There was an error while creating a $thing. Depending on the error
1259 # we want to abort the whole transaction, or only rollback the
1260 # changes related to the creation of this $thing
1261
1262 # Abort the whole job
1263 if ($@ =~ /horrible_problem/) {
1264 print "something horrible happend, aborting job!";
1265 die $@; # rethrow error
1266 }
1267
1268 # Ignore this $thing, report the error, and continue with the
1269 # next $thing
1270 print "Cannot create thing: $@";
1271 }
1272 # There was no error, so save all changes since the last
1273 # savepoint.
1274
1275 # SQL: RELEASE SAVEPOINT savepoint_0;
1276 }
1277 });
1278 };
1279 if ($@) {
1280 # There was an error while handling the $job. Rollback all changes
1281 # since the transaction started, including the already committed
1282 # ('released') savepoints. There will be neither a new $job nor any
1283 # $thing entry in the database.
1284
1285 # SQL: ROLLBACK;
1286
1287 print "ERROR: $@\n";
1288 }
1289 else {
1290 # There was no error while handling the $job. Commit all changes.
1291 # Only now other connections can see the newly created $job and
1292 # @things.
1293
1294 # SQL: COMMIT;
1295
1296 print "Ok\n";
1297 }
1298
1299 In this example it might be hard to see where the rollbacks, releases
1300 and commits are happening, but it works just the same as for plain
1301 <txn_do>: If the "eval"-block around "txn_do" fails, a rollback is
1302 issued. If the "eval" succeeds, the transaction is committed (or the
1303 savepoint released).
1304
1305 While you can get more fine-grained controll using "svp_begin",
1306 "svp_release" and "svp_rollback", it is strongly recommended to use
1307 "txn_do" with coderefs.
1308
1310 Creating Schemas From An Existing Database
1311 DBIx::Class::Schema::Loader will connect to a database and create a
1312 DBIx::Class::Schema and associated sources by examining the database.
1313
1314 The recommend way of achieving this is to use the make_schema_at
1315 method:
1316
1317 perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:./lib \
1318 -e 'make_schema_at("My::Schema", { debug => 1 }, [ "dbi:Pg:dbname=foo","postgres" ])'
1319
1320 This will create a tree of files rooted at "./lib/My/Schema/"
1321 containing source definitions for all the tables found in the "foo"
1322 database.
1323
1324 Creating DDL SQL
1325 The following functionality requires you to have SQL::Translator (also
1326 known as "SQL Fairy") installed.
1327
1328 To create a set of database-specific .sql files for the above schema:
1329
1330 my $schema = My::Schema->connect($dsn);
1331 $schema->create_ddl_dir(['MySQL', 'SQLite', 'PostgreSQL'],
1332 '0.1',
1333 './dbscriptdir/'
1334 );
1335
1336 By default this will create schema files in the current directory, for
1337 MySQL, SQLite and PostgreSQL, using the $VERSION from your Schema.pm.
1338
1339 To create a new database using the schema:
1340
1341 my $schema = My::Schema->connect($dsn);
1342 $schema->deploy({ add_drop_table => 1});
1343
1344 To import created .sql files using the mysql client:
1345
1346 mysql -h "host" -D "database" -u "user" -p < My_Schema_1.0_MySQL.sql
1347
1348 To create "ALTER TABLE" conversion scripts to update a database to a
1349 newer version of your schema at a later point, first set a new $VERSION
1350 in your Schema file, then:
1351
1352 my $schema = My::Schema->connect($dsn);
1353 $schema->create_ddl_dir(['MySQL', 'SQLite', 'PostgreSQL'],
1354 '0.2',
1355 '/dbscriptdir/',
1356 '0.1'
1357 );
1358
1359 This will produce new database-specific .sql files for the new version
1360 of the schema, plus scripts to convert from version 0.1 to 0.2. This
1361 requires that the files for 0.1 as created above are available in the
1362 given directory to diff against.
1363
1364 Select from dual
1365 Dummy tables are needed by some databases to allow calling functions or
1366 expressions that aren't based on table content, for examples of how
1367 this applies to various database types, see:
1368 http://troels.arvin.dk/db/rdbms/#other-dummy_table
1369 <http://troels.arvin.dk/db/rdbms/#other-dummy_table>.
1370
1371 Note: If you're using Oracles dual table don't ever do anything other
1372 than a select, if you CRUD on your dual table you *will* break your
1373 database.
1374
1375 Make a table class as you would for any other table
1376
1377 package MyAppDB::Dual;
1378 use strict;
1379 use warnings;
1380 use base 'DBIx::Class::Core';
1381 __PACKAGE__->table("Dual");
1382 __PACKAGE__->add_columns(
1383 "dummy",
1384 { data_type => "VARCHAR2", is_nullable => 0, size => 1 },
1385 );
1386
1387 Once you've loaded your table class select from it using "select" and
1388 "as" instead of "columns"
1389
1390 my $rs = $schema->resultset('Dual')->search(undef,
1391 { select => [ 'sydate' ],
1392 as => [ 'now' ]
1393 },
1394 );
1395
1396 All you have to do now is be careful how you access your resultset, the
1397 below will not work because there is no column called 'now' in the Dual
1398 table class
1399
1400 while (my $dual = $rs->next) {
1401 print $dual->now."\n";
1402 }
1403 # Can't locate object method "now" via package "MyAppDB::Dual" at headshot.pl line 23.
1404
1405 You could of course use 'dummy' in "as" instead of 'now', or
1406 "add_columns" to your Dual class for whatever you wanted to select from
1407 dual, but that's just silly, instead use "get_column"
1408
1409 while (my $dual = $rs->next) {
1410 print $dual->get_column('now')."\n";
1411 }
1412
1413 Or use "cursor"
1414
1415 my $cursor = $rs->cursor;
1416 while (my @vals = $cursor->next) {
1417 print $vals[0]."\n";
1418 }
1419
1420 In case you're going to use this "trick" together with "deploy" in
1421 DBIx::Class::Schema or "create_ddl_dir" in DBIx::Class::Schema a table
1422 called "dual" will be created in your current schema. This would
1423 overlap "sys.dual" and you could not fetch "sysdate" or
1424 "sequence.nextval" anymore from dual. To avoid this problem, just tell
1425 SQL::Translator to not create table dual:
1426
1427 my $sqlt_args = {
1428 add_drop_table => 1,
1429 parser_args => { sources => [ grep $_ ne 'Dual', schema->sources ] },
1430 };
1431 $schema->create_ddl_dir( [qw/Oracle/], undef, './sql', undef, $sqlt_args );
1432
1433 Or use DBIx::Class::ResultClass::HashRefInflator
1434
1435 $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
1436 while ( my $dual = $rs->next ) {
1437 print $dual->{now}."\n";
1438 }
1439
1440 Here are some example "select" conditions to illustrate the different
1441 syntax you could use for doing stuff like
1442 "oracles.heavily(nested(functions_can('take', 'lots'), OF), 'args')"
1443
1444 # get a sequence value
1445 select => [ 'A_SEQ.nextval' ],
1446
1447 # get create table sql
1448 select => [ { 'dbms_metadata.get_ddl' => [ "'TABLE'", "'ARTIST'" ]} ],
1449
1450 # get a random num between 0 and 100
1451 select => [ { "trunc" => [ { "dbms_random.value" => [0,100] } ]} ],
1452
1453 # what year is it?
1454 select => [ { 'extract' => [ \'year from sysdate' ] } ],
1455
1456 # do some math
1457 select => [ {'round' => [{'cos' => [ \'180 * 3.14159265359/180' ]}]}],
1458
1459 # which day of the week were you born on?
1460 select => [{'to_char' => [{'to_date' => [ "'25-DEC-1980'", "'dd-mon-yyyy'" ]}, "'day'"]}],
1461
1462 # select 16 rows from dual
1463 select => [ "'hello'" ],
1464 as => [ 'world' ],
1465 group_by => [ 'cube( 1, 2, 3, 4 )' ],
1466
1467 Adding Indexes And Functions To Your SQL
1468 Often you will want indexes on columns on your table to speed up
1469 searching. To do this, create a method called "sqlt_deploy_hook" in the
1470 relevant source class (refer to the advanced callback system if you
1471 wish to share a hook between multiple sources):
1472
1473 package My::Schema::Result::Artist;
1474
1475 __PACKAGE__->table('artist');
1476 __PACKAGE__->add_columns(id => { ... }, name => { ... })
1477
1478 sub sqlt_deploy_hook {
1479 my ($self, $sqlt_table) = @_;
1480
1481 $sqlt_table->add_index(name => 'idx_name', fields => ['name']);
1482 }
1483
1484 1;
1485
1486 Sometimes you might want to change the index depending on the type of
1487 the database for which SQL is being generated:
1488
1489 my ($db_type = $sqlt_table->schema->translator->producer_type)
1490 =~ s/^SQL::Translator::Producer:://;
1491
1492 You can also add hooks to the schema level to stop certain tables being
1493 created:
1494
1495 package My::Schema;
1496
1497 ...
1498
1499 sub sqlt_deploy_hook {
1500 my ($self, $sqlt_schema) = @_;
1501
1502 $sqlt_schema->drop_table('table_name');
1503 }
1504
1505 You could also add views, procedures or triggers to the output using
1506 "add_view" in SQL::Translator::Schema, "add_procedure" in
1507 SQL::Translator::Schema or "add_trigger" in SQL::Translator::Schema.
1508
1509 Schema versioning
1510 The following example shows simplistically how you might use
1511 DBIx::Class to deploy versioned schemas to your customers. The basic
1512 process is as follows:
1513
1514 1. Create a DBIx::Class schema
1515
1516 2. Save the schema
1517
1518 3. Deploy to customers
1519
1520 4. Modify schema to change functionality
1521
1522 5. Deploy update to customers
1523
1524 Create a DBIx::Class schema
1525
1526 This can either be done manually, or generated from an existing
1527 database as described under "Creating Schemas From An Existing
1528 Database"
1529
1530 Save the schema
1531
1532 Call "create_ddl_dir" in DBIx::Class::Schema as above under "Creating
1533 DDL SQL".
1534
1535 Deploy to customers
1536
1537 There are several ways you could deploy your schema. These are probably
1538 beyond the scope of this recipe, but might include:
1539
1540 1. Require customer to apply manually using their RDBMS.
1541
1542 2. Package along with your app, making database dump/schema
1543 update/tests all part of your install.
1544
1545 Modify the schema to change functionality
1546
1547 As your application evolves, it may be necessary to modify your schema
1548 to change functionality. Once the changes are made to your schema in
1549 DBIx::Class, export the modified schema and the conversion scripts as
1550 in "Creating DDL SQL".
1551
1552 Deploy update to customers
1553
1554 Add the DBIx::Class::Schema::Versioned schema component to your Schema
1555 class. This will add a new table to your database called
1556 "dbix_class_schema_vesion" which will keep track of which version is
1557 installed and warn if the user tries to run a newer schema version than
1558 the database thinks it has.
1559
1560 Alternatively, you can send the conversion SQL scripts to your
1561 customers as above.
1562
1563 Setting quoting for the generated SQL
1564 If the database contains column names with spaces and/or reserved
1565 words, they need to be quoted in the SQL queries. This is done using:
1566
1567 $schema->storage->sql_maker->quote_char([ qw/[ ]/] );
1568 $schema->storage->sql_maker->name_sep('.');
1569
1570 The first sets the quote characters. Either a pair of matching
1571 brackets, or a """ or "'":
1572
1573 $schema->storage->sql_maker->quote_char('"');
1574
1575 Check the documentation of your database for the correct quote
1576 characters to use. "name_sep" needs to be set to allow the SQL
1577 generator to put the quotes the correct place.
1578
1579 In most cases you should set these as part of the arguments passed to
1580 "connect" in DBIx::Class::Schema:
1581
1582 my $schema = My::Schema->connect(
1583 'dbi:mysql:my_db',
1584 'db_user',
1585 'db_password',
1586 {
1587 quote_char => '"',
1588 name_sep => '.'
1589 }
1590 )
1591
1592 In some cases, quoting will be required for all users of a schema. To
1593 enforce this, you can also overload the "connection" method for your
1594 schema class:
1595
1596 sub connection {
1597 my $self = shift;
1598 my $rv = $self->next::method( @_ );
1599 $rv->storage->sql_maker->quote_char([ qw/[ ]/ ]);
1600 $rv->storage->sql_maker->name_sep('.');
1601 return $rv;
1602 }
1603
1604 Setting limit dialect for SQL::Abstract::Limit
1605 In some cases, SQL::Abstract::Limit cannot determine the dialect of the
1606 remote SQL server by looking at the database handle. This is a common
1607 problem when using the DBD::JDBC, since the DBD-driver only know that
1608 in has a Java-driver available, not which JDBC driver the Java
1609 component has loaded. This specifically sets the limit_dialect to
1610 Microsoft SQL-server (See more names in SQL::Abstract::Limit
1611 -documentation.
1612
1613 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
1614
1615 The JDBC bridge is one way of getting access to a MSSQL server from a
1616 platform that Microsoft doesn't deliver native client libraries for.
1617 (e.g. Linux)
1618
1619 The limit dialect can also be set at connect time by specifying a
1620 "limit_dialect" key in the final hash as shown above.
1621
1622 Working with PostgreSQL array types
1623 You can also assign values to PostgreSQL array columns by passing array
1624 references in the "\%columns" ("\%vals") hashref of the "create" in
1625 DBIx::Class::ResultSet and "update" in DBIx::Class::Row family of
1626 methods:
1627
1628 $resultset->create({
1629 numbers => [1, 2, 3]
1630 });
1631
1632 $row->update(
1633 {
1634 numbers => [1, 2, 3]
1635 },
1636 {
1637 day => '2008-11-24'
1638 }
1639 );
1640
1641 In conditions (e.g. "\%cond" in the "search" in DBIx::Class::ResultSet
1642 family of methods) you cannot directly use array references (since this
1643 is interpreted as a list of values to be "OR"ed), but you can use the
1644 following syntax to force passing them as bind values:
1645
1646 $resultset->search(
1647 {
1648 numbers => \[ '= ?', [numbers => [1, 2, 3]] ]
1649 }
1650 );
1651
1652 See "array_datatypes" in SQL::Abstract and "Literal SQL with
1653 placeholders and bind values (subqueries)" in SQL::Abstract for more
1654 explanation. Note that DBIx::Class sets "bindtype" in SQL::Abstract to
1655 "columns", so you must pass the bind values (the "[1, 2, 3]" arrayref
1656 in the above example) wrapped in arrayrefs together with the column
1657 name, like this: "[column_name => value]".
1658
1660 Easy migration from class-based to schema-based setup
1661 You want to start using the schema-based approach to DBIx::Class (see
1662 SchemaIntro.pod), but have an established class-based setup with lots
1663 of existing classes that you don't want to move by hand. Try this nifty
1664 script instead:
1665
1666 use MyDB;
1667 use SQL::Translator;
1668
1669 my $schema = MyDB->schema_instance;
1670
1671 my $translator = SQL::Translator->new(
1672 debug => $debug || 0,
1673 trace => $trace || 0,
1674 no_comments => $no_comments || 0,
1675 show_warnings => $show_warnings || 0,
1676 add_drop_table => $add_drop_table || 0,
1677 validate => $validate || 0,
1678 parser_args => {
1679 'DBIx::Schema' => $schema,
1680 },
1681 producer_args => {
1682 'prefix' => 'My::Schema',
1683 },
1684 );
1685
1686 $translator->parser('SQL::Translator::Parser::DBIx::Class');
1687 $translator->producer('SQL::Translator::Producer::DBIx::Class::File');
1688
1689 my $output = $translator->translate(@args) or die
1690 "Error: " . $translator->error;
1691
1692 print $output;
1693
1694 You could use Module::Find to search for all subclasses in the MyDB::*
1695 namespace, which is currently left as an exercise for the reader.
1696
1698 DBIx::Class uses the Class::C3 package, which provides for redispatch
1699 of method calls, useful for things like default values and triggers.
1700 You have to use calls to "next::method" to overload methods. More
1701 information on using Class::C3 with DBIx::Class can be found in
1702 DBIx::Class::Manual::Component.
1703
1704 Setting default values for a row
1705 It's as simple as overriding the "new" method. Note the use of
1706 "next::method".
1707
1708 sub new {
1709 my ( $class, $attrs ) = @_;
1710
1711 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
1712
1713 my $new = $class->next::method($attrs);
1714
1715 return $new;
1716 }
1717
1718 For more information about "next::method", look in the Class::C3
1719 documentation. See also DBIx::Class::Manual::Component for more ways to
1720 write your own base classes to do this.
1721
1722 People looking for ways to do "triggers" with DBIx::Class are probably
1723 just looking for this.
1724
1725 Changing one field whenever another changes
1726 For example, say that you have three columns, "id", "number", and
1727 "squared". You would like to make changes to "number" and have
1728 "squared" be automagically set to the value of "number" squared. You
1729 can accomplish this by overriding "store_column":
1730
1731 sub store_column {
1732 my ( $self, $name, $value ) = @_;
1733 if ($name eq 'number') {
1734 $self->squared($value * $value);
1735 }
1736 $self->next::method($name, $value);
1737 }
1738
1739 Note that the hard work is done by the call to "next::method", which
1740 redispatches your call to store_column in the superclass(es).
1741
1742 Automatically creating related objects
1743 You might have a class "Artist" which has many "CD"s. Further, you
1744 want to create a "CD" object every time you insert an "Artist" object.
1745 You can accomplish this by overriding "insert" on your objects:
1746
1747 sub insert {
1748 my ( $self, @args ) = @_;
1749 $self->next::method(@args);
1750 $self->cds->new({})->fill_from_artist($self)->insert;
1751 return $self;
1752 }
1753
1754 where "fill_from_artist" is a method you specify in "CD" which sets
1755 values in "CD" based on the data in the "Artist" object you pass in.
1756
1757 Wrapping/overloading a column accessor
1758 Problem:
1759
1760 Say you have a table "Camera" and want to associate a description with
1761 each camera. For most cameras, you'll be able to generate the
1762 description from the other columns. However, in a few special cases you
1763 may want to associate a custom description with a camera.
1764
1765 Solution:
1766
1767 In your database schema, define a description field in the "Camera"
1768 table that can contain text and null values.
1769
1770 In DBIC, we'll overload the column accessor to provide a sane default
1771 if no custom description is defined. The accessor will either return or
1772 generate the description, depending on whether the field is null or
1773 not.
1774
1775 First, in your "Camera" schema class, define the description field as
1776 follows:
1777
1778 __PACKAGE__->add_columns(description => { accessor => '_description' });
1779
1780 Next, we'll define the accessor-wrapper subroutine:
1781
1782 sub description {
1783 my $self = shift;
1784
1785 # If there is an update to the column, we'll let the original accessor
1786 # deal with it.
1787 return $self->_description(@_) if @_;
1788
1789 # Fetch the column value.
1790 my $description = $self->_description;
1791
1792 # If there's something in the description field, then just return that.
1793 return $description if defined $description && length $descripton;
1794
1795 # Otherwise, generate a description.
1796 return $self->generate_description;
1797 }
1798
1800 DBIx::Class objects with Data::Dumper
1801 Data::Dumper can be a very useful tool for debugging, but sometimes it
1802 can be hard to find the pertinent data in all the data it can generate.
1803 Specifically, if one naively tries to use it like so,
1804
1805 use Data::Dumper;
1806
1807 my $cd = $schema->resultset('CD')->find(1);
1808 print Dumper($cd);
1809
1810 several pages worth of data from the CD object's schema and result
1811 source will be dumped to the screen. Since usually one is only
1812 interested in a few column values of the object, this is not very
1813 helpful.
1814
1815 Luckily, it is possible to modify the data before Data::Dumper outputs
1816 it. Simply define a hook that Data::Dumper will call on the object
1817 before dumping it. For example,
1818
1819 package My::DB::CD;
1820
1821 sub _dumper_hook {
1822 $_[0] = bless {
1823 %{ $_[0] },
1824 result_source => undef,
1825 }, ref($_[0]);
1826 }
1827
1828 [...]
1829
1830 use Data::Dumper;
1831
1832 local $Data::Dumper::Freezer = '_dumper_hook';
1833
1834 my $cd = $schema->resultset('CD')->find(1);
1835 print Dumper($cd);
1836 # dumps $cd without its ResultSource
1837
1838 If the structure of your schema is such that there is a common base
1839 class for all your table classes, simply put a method similar to
1840 "_dumper_hook" in the base class and set $Data::Dumper::Freezer to its
1841 name and Data::Dumper will automagically clean up your data before
1842 printing it. See "EXAMPLES" in Data::Dumper for more information.
1843
1844 Profiling
1845 When you enable DBIx::Class::Storage's debugging it prints the SQL
1846 executed as well as notifications of query completion and transaction
1847 begin/commit. If you'd like to profile the SQL you can subclass the
1848 DBIx::Class::Storage::Statistics class and write your own profiling
1849 mechanism:
1850
1851 package My::Profiler;
1852 use strict;
1853
1854 use base 'DBIx::Class::Storage::Statistics';
1855
1856 use Time::HiRes qw(time);
1857
1858 my $start;
1859
1860 sub query_start {
1861 my $self = shift();
1862 my $sql = shift();
1863 my $params = @_;
1864
1865 $self->print("Executing $sql: ".join(', ', @params)."\n");
1866 $start = time();
1867 }
1868
1869 sub query_end {
1870 my $self = shift();
1871 my $sql = shift();
1872 my @params = @_;
1873
1874 my $elapsed = sprintf("%0.4f", time() - $start);
1875 $self->print("Execution took $elapsed seconds.\n");
1876 $start = undef;
1877 }
1878
1879 1;
1880
1881 You can then install that class as the debugging object:
1882
1883 __PACKAGE__->storage->debugobj(new My::Profiler());
1884 __PACKAGE__->storage->debug(1);
1885
1886 A more complicated example might involve storing each execution of SQL
1887 in an array:
1888
1889 sub query_end {
1890 my $self = shift();
1891 my $sql = shift();
1892 my @params = @_;
1893
1894 my $elapsed = time() - $start;
1895 push(@{ $calls{$sql} }, {
1896 params => \@params,
1897 elapsed => $elapsed
1898 });
1899 }
1900
1901 You could then create average, high and low execution times for an SQL
1902 statement and dig down to see if certain parameters cause aberrant
1903 behavior. You might want to check out DBIx::Class::QueryLog as well.
1904
1906 DBIx::Class programs can have a significant startup delay as the ORM
1907 loads all the relevant classes. This section examines techniques for
1908 reducing the startup delay.
1909
1910 These tips are are listed in order of decreasing effectiveness - so the
1911 first tip, if applicable, should have the greatest effect on your
1912 application.
1913
1914 Statically Define Your Schema
1915 If you are using DBIx::Class::Schema::Loader to build the classes
1916 dynamically based on the database schema then there will be a
1917 significant startup delay.
1918
1919 For production use a statically defined schema (which can be generated
1920 using DBIx::Class::Schema::Loader to dump the database schema once -
1921 see make_schema_at and dump_directory for more details on creating
1922 static schemas from a database).
1923
1924 Move Common Startup into a Base Class
1925 Typically DBIx::Class result classes start off with
1926
1927 use base qw/DBIx::Class::Core/;
1928 __PACKAGE__->load_components(qw/InflateColumn::DateTime/);
1929
1930 If this preamble is moved into a common base class:-
1931
1932 package MyDBICbase;
1933
1934 use base qw/DBIx::Class::Core/;
1935 __PACKAGE__->load_components(qw/InflateColumn::DateTime/);
1936 1;
1937
1938 and each result class then uses this as a base:-
1939
1940 use base qw/MyDBICbase/;
1941
1942 then the load_components is only performed once, which can result in a
1943 considerable startup speedup for schemas with many classes.
1944
1945 Explicitly List Schema Result Classes
1946 The schema class will normally contain
1947
1948 __PACKAGE__->load_classes();
1949
1950 to load the result classes. This will use Module::Find to find and load
1951 the appropriate modules. Explicitly defining the classes you wish to
1952 load will remove the overhead of Module::Find and the related directory
1953 operations:
1954
1955 __PACKAGE__->load_classes(qw/ CD Artist Track /);
1956
1957 If you are instead using the load_namespaces syntax to load the
1958 appropriate classes there is not a direct alternative avoiding
1959 Module::Find.
1960
1962 Cached statements
1963 DBIx::Class normally caches all statements with prepare_cached(). This
1964 is normally a good idea, but if too many statements are cached, the
1965 database may use too much memory and may eventually run out and fail
1966 entirely. If you suspect this may be the case, you may want to examine
1967 DBI's CachedKids hash:
1968
1969 # print all currently cached prepared statements
1970 print for keys %{$schema->storage->dbh->{CachedKids}};
1971 # get a count of currently cached prepared statements
1972 my $count = scalar keys %{$schema->storage->dbh->{CachedKids}};
1973
1974 If it's appropriate, you can simply clear these statements,
1975 automatically deallocating them in the database:
1976
1977 my $kids = $schema->storage->dbh->{CachedKids};
1978 delete @{$kids}{keys %$kids} if scalar keys %$kids > 100;
1979
1980 But what you probably want is to expire unused statements and not those
1981 that are used frequently. You can accomplish this with Tie::Cache or
1982 Tie::Cache::LRU:
1983
1984 use Tie::Cache;
1985 use DB::Main;
1986 my $schema = DB::Main->connect($dbi_dsn, $user, $pass, {
1987 on_connect_do => sub { tie %{shift->_dbh->{CachedKids}}, 'Tie::Cache', 100 },
1988 });
1989
1990
1991
1992perl v5.12.0 2010-05-12 DBIx::Class::Manual::Cookbook(3)