X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FManual%2FCookbook.pod;h=3e5aa7b61870a9e8f4784c6e6399ad76ffd96c1a;hb=541df64afe67cde2a5cd2c48c1cb419298452a1f;hp=a9b9aaa70d98be847f80020bbba035bf7ea24e16;hpb=709353afc62951025fc2d497eb0f33bd6052a98a;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Manual/Cookbook.pod b/lib/DBIx/Class/Manual/Cookbook.pod index a9b9aaa..3e5aa7b 100644 --- a/lib/DBIx/Class/Manual/Cookbook.pod +++ b/lib/DBIx/Class/Manual/Cookbook.pod @@ -70,6 +70,56 @@ This results in the following C clause: For more information on generating complex queries, see L. +=head3 Arbitrary SQL through a custom ResultSource + +Sometimes you have to run arbitrary SQL because your query is too complex +(e.g. it contains Unions, Sub-Selects, Stored Procedures, etc.) or has to +be optimized for your database in a special way, but you still want to +get the results as a L. +The recommended way to accomplish this is by defining a separate ResultSource +for your query. You can then inject complete SQL statements using a scalar +reference (this is a feature of L). + +Say you want to run a complex custom query on your user data, here's what +you have to add to your User class: + + package My::Schema::User; + + use base qw/DBIx::Class/; + + # ->load_components, ->table, ->add_columns, etc. + + # Make a new ResultSource based on the User class + my $source = __PACKAGE__->result_source_instance(); + my $new_source = $source->new( $source ); + $new_source->source_name( 'UserFriendsComplex' ); + + # Hand in your query as a scalar reference + # It will be added as a sub-select after FROM, + # so pay attention to the surrounding brackets! + $new_source->name( \<register_source( 'UserFriendsComplex' => $new_source ); + +Next, you can execute your complex query using bind parameters like this: + + my $friends = [ $schema->resultset( 'UserFriendsComplex' )->search( {}, + { + bind => [ 12345, 12345 ] + } + ) ]; + +... and you'll get back a perfect L. + =head3 Using specific columns When you only want specific columns from a table, you can use @@ -107,12 +157,15 @@ to access the returned value: ); # Equivalent SQL: - # SELECT name name, LENGTH( name ) name_length + # SELECT name name, LENGTH( name ) # FROM artist -If your alias exists as a column in your base class (i.e. it was added -with C), you just access it as normal. Our C -class has a C column, so we just use the C accessor: +Note that the C< as > attribute has absolutely nothing to with the sql +syntax C< SELECT foo AS bar > (see the documentation in +L). If your alias exists as a +column in your base class (i.e. it was added with C), you +just access it as normal. Our C class has a C column, so +we just use the C accessor: my $artist = $rs->first(); my $name = $artist->name(); @@ -139,7 +192,7 @@ any of your aliases using either of these: select => [ { distinct => [ $source->columns ] } ], - as => [ $source->columns ] + as => [ $source->columns ] # remember 'as' is not the same as SQL AS :-) } ); @@ -176,6 +229,10 @@ L supports C as follows: # LEFT JOIN cd cds ON ( cds.artist = me.artistid ) # GROUP BY name +Please see L documentation if you +are in any way unsure about the use of the attributes above (C< join +>, C< select >, C< as > and C< group_by >). + =head3 Predefined searches You can write your own L class by inheriting from it @@ -415,7 +472,7 @@ ways, the obvious one is to use search: {}, { select => [ { sum => 'Cost' } ], - as => [ 'total_cost' ], + as => [ 'total_cost' ], # remember this 'as' is for DBIx::Class::ResultSet not SQL } ); my $tc = $rs->first->get_column('total_cost'); @@ -487,7 +544,7 @@ To order C<< $book->pages >> by descending page_number. =head2 Transactions As of version 0.04001, there is improved transaction support in -L and L. Here is an +L and L. Here is an example of the recommended way to use it: my $genus = $schema->resultset('Genus')->find(12); @@ -526,7 +583,7 @@ in the future. =head2 Many-to-many relationships -This is straightforward using L: +This is straightforward using L: package My::DB; # ... set up connection ... @@ -568,7 +625,9 @@ C. $attrs->{foo} = 'bar' unless defined $attrs->{foo}; - $class->next::method($attrs); + my $new = $class->next::method($attrs); + + return $new; } For more information about C, look in the L @@ -586,7 +645,7 @@ module. To make an object stringify itself as a single column, use something like this (replace C with the column/method of your choice): - use overload '""' => 'foo', fallback => 1; + use overload '""' => sub { shift->name}, fallback => 1; For more complex stringification, you can use an anonymous subroutine: @@ -905,7 +964,7 @@ method. =head2 Profiling -When you enable L's debugging it prints the SQL +When you enable L's debugging it prints the SQL executed as well as notifications of query completion and transaction begin/commit. If you'd like to profile the SQL you can subclass the L class and write your own profiling @@ -989,7 +1048,7 @@ seperate proxy-class files for this. We would be copying all the user methods into the Admin class. There is a cleaner way to accomplish this. -Overriding the C method within the User proxy-class +Overriding the C method within the User proxy-class gives us the effect we want. This method is called by L when inflating a result from storage. So we grab the object being returned, inspect the values we are looking for, @@ -1096,4 +1155,85 @@ B test.pl ### The statement below will print print "I can do admin stuff\n" if $admin->can('do_admin_stuff'); +=head2 Skip object creation for faster results + +DBIx::Class is not built for speed, it's built for convenience and +ease of use, but sometimes you just need to get the data, and skip the +fancy objects. + +To do this simply use L. + + my $rs = $schema->resultset('CD'); + + $rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + my $hash_ref = $rs->find(1); + +Wasn't that easy? + +=head2 Get raw data for blindingly fast results + +If the C solution above is not fast enough for you, you +can use a DBIx::Class to return values exactly as they come out of the +data base with none of the convenience methods wrapped round them. + +This is used like so:- + + my $cursor = $rs->cursor + while (my @vals = $cursor->next) { + # use $val[0..n] here + } + +You will need to map the array offsets to particular columns (you can +use the I