=head1 NAME
-DBIx::Class::Manual::Cookbook - Misc recipes
+DBIx::Class::Manual::Cookbook - Miscellaneous recipes
-=head1 DESCRIPTION
+=head1 RECIPES
-Things that could be handy
+=head2 Complex searches
-=head1 RECIPES
+Sometimes you need to formulate a query using specific operators:
+
+ my @albums = MyApp::DB::Album->search({
+ artist => { 'like', '%Lamb%' },
+ title => { 'like', '%Fear of Fours%' },
+ });
+
+This results in something like the following C<WHERE> clause:
+
+ WHERE artist LIKE '%Lamb%' AND title LIKE '%Fear of Fours%'
+
+Other queries might require slightly more complex logic:
+
+ my @albums = MyApp::DB::Album->search({
+ -or => [
+ -and => [
+ artist => { 'like', '%Smashing Pumpkins%' },
+ title => 'Siamese Dream',
+ ],
+ artist => 'Starchildren',
+ ],
+ });
+
+This results in the following C<WHERE> clause:
+
+ WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' )
+ OR artist = 'Starchildren'
+
+For more information on generating complex queries, see
+L<SQL::Abstract/WHERE CLAUSES>.
=head2 Disconnecting cleanly
-If you find yourself quitting an app with Control-C a lot during development,
-you might like to put the following signal handler in your main database
-class to make sure it disconnects cleanly:
+If you find yourself quitting an app with Control-C a lot during
+development, you might like to put the following signal handler in
+your main database class to make sure it disconnects cleanly:
$SIG{INT} = sub {
__PACKAGE__->storage->dbh->disconnect;
=head2 Using joins and prefetch
-See L<DBIx::Class::ResultSet/Attributes>.
+See L<DBIx::Class::ResultSet/ATTRIBUTES>.
=head2 Transactions
As of version 0.04001, there is improved transaction support in
-L<DBIx::Class::Storage::DBI>. Here is an example of the recommended way to use it:
+L<DBIx::Class::Storage::DBI>. Here is an example of the recommended
+way to use it:
- my $obj = Genus->find(12);
+ my $genus = Genus->find(12);
eval {
MyDB->txn_begin;
- $obj->add_to_species({ name => 'troglodyte' });
- $obj->wings(2);
- $obj->update;
- cromulate($obj); # can have a nested transation
+ $genus->add_to_species({ name => 'troglodyte' });
+ $genus->wings(2);
+ $genus->update;
+ cromulate($genus); # Can have a nested transation
MyDB->txn_commit;
};
- if ($@) { eval { MyDB->txn_rollback } } # rollback might fail, too
+ if ($@) {
+ # Rollback might fail, too
+ eval {
+ MyDB->txn_rollback
+ };
+ }
-Currently, a nested commit will do nothing and a nested rollback will die.
-The code at each level must be sure to call rollback in the case of an error,
-to ensure that the rollback will propagate to the top level and be issued.
-Support for savepoints and for true nested transactions (for databases that
-support them) will hopefully be added in the future.
+Currently, a nested commit will do nothing and a nested rollback will
+die. The code at each level must be sure to call rollback in the case
+of an error, to ensure that the rollback will propagate to the top
+level and be issued. Support for savepoints and for true nested
+transactions (for databases that support them) will hopefully be added
+in the future.
=head2 Many-to-many relationships
-This is not as easy as it could be, but it's possible. Here's an example to
-illustrate:
-
- # Set up inherited connection information
- package MyApp::DBIC;
- use base qw/DBIx::Class/;
-
- __PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
- __PACKAGE__->connection(...);
-
- # Set up a class for the 'authors' table
- package MyApp::DBIC::Author;
- use base qw/MyApp::DBIC/;
-
- __PACKAGE__->table('authors');
- __PACKAGE__->add_columns(qw/authID first_name last_name/);
- __PACKAGE__->set_primary_key(qw/authID/);
-
- # Define relationship to the link table
- __PACKAGE__->has_many('b2a' => 'MyApp::DBIC::Book2Author', 'authID');
-
- # Create the accessor for books from the ::Author class
- sub books {
- my ($self) = @_;
- return MyApp::DBIC::Book->search(
- { 'b2a.authID' => $self->authID }, # WHERE clause
- { join => 'b2a' } # join condition (part of search attrs)
- # 'b2a' refers to the relationship named earlier in the Author class.
- # 'b2a.authID' refers to the authID column of the b2a relationship,
- # which becomes accessible in the search by being joined.
- );
- }
-
- # define the link table class
- package MyApp::DBIC::Book2Author;
- use base qw/MyApp::DBIC/;
-
- __PACKAGE__->table('book2author');
- __PACKAGE__->add_columns(qw/bookID authID/);
- __PACKAGE__->set_primary_key(qw/bookID authID/);
-
- __PACKAGE__->belongs_to('authID' => 'MyApp::DBIC::Author');
- __PACKAGE__->belongs_to('bookID' => 'MyApp::DBIC::Book');
-
- package MyApp::DBIC::Book;
- use base qw/MyApp::DBIC/;
-
- __PACKAGE__->table('books');
- __PACKAGE__->add_columns(qw/bookID title edition isbn publisher year/);
- __PACKAGE__->set_primary_key(qw/bookID/);
-
- __PACKAGE__->has_many('b2a' => 'MyApp::DBIC::Book2Author', 'bookID');
-
- sub authors {
- my ($self) = @_;
- return MyApp::DBIC::Author->search(
- { 'b2a.bookID' => $self->bookID }, # WHERE clause
- { join => 'b2a' }); # join condition (part of search attrs)
- }
-
- # So the above search returns an author record where the bookID field of the
- # book2author table equals the bookID of the books (using the bookID
- # relationship table
+This is not as easy as it could be, but it's possible. Here's an
+example to illustrate:
+
+ # Set up inherited connection information
+ package MyApp::DBIC;
+ use base qw/DBIx::Class/;
+
+ __PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
+ __PACKAGE__->connection(...);
+
+ # Set up a class for the 'authors' table
+ package MyApp::DBIC::Author;
+ use base qw/MyApp::DBIC/;
+
+ __PACKAGE__->table('authors');
+ __PACKAGE__->add_columns(qw/authID first_name last_name/);
+ __PACKAGE__->set_primary_key(qw/authID/);
+
+ # Define relationship to the link table
+ __PACKAGE__->has_many('b2a' => 'MyApp::DBIC::Book2Author', 'authID');
+
+ # Create the accessor for books from the Author class
+ sub books {
+ my ($self) = @_;
+ return MyApp::DBIC::Book->search(
+ { 'b2a.authID' => $self->authID }, # WHERE clause
+ { join => 'b2a' } # join condition (part of search attrs)
+ # 'b2a' refers to the relationship named earlier in the Author class.
+ # 'b2a.authID' refers to the authID column of the b2a relationship,
+ # which becomes accessible in the search by being joined.
+ );
+ }
+
+ # Define the link table class
+ package MyApp::DBIC::Book2Author;
+ use base qw/MyApp::DBIC/;
+
+ __PACKAGE__->table('book2author');
+ __PACKAGE__->add_columns(qw/bookID authID/);
+ __PACKAGE__->set_primary_key(qw/bookID authID/);
+
+ __PACKAGE__->belongs_to('authID' => 'MyApp::DBIC::Author');
+ __PACKAGE__->belongs_to('bookID' => 'MyApp::DBIC::Book');
+
+ package MyApp::DBIC::Book;
+ use base qw/MyApp::DBIC/;
+
+ __PACKAGE__->table('books');
+ __PACKAGE__->add_columns(qw/bookID title edition isbn publisher year/);
+ __PACKAGE__->set_primary_key(qw/bookID/);
+
+ __PACKAGE__->has_many('b2a' => 'MyApp::DBIC::Book2Author', 'bookID');
+
+
+ # Returns an author record where the bookID field of the
+ # book2author table equals the bookID of the books (using the
+ # bookID relationship table)
+ sub authors {
+ my ($self) = @_;
+ return MyApp::DBIC::Author->search(
+ { 'b2a.bookID' => $self->bookID }, # WHERE clause
+ { join => 'b2a' } # JOIN condition
+ );
+ }
=head2 Setting default values
-It's as simple as overriding the C<new> method. Note the use of C<next::method>.
+It's as simple as overriding the C<new> method. Note the use of
+C<next::method>.
sub new {
- my( $class, $attrs ) = @_;
-
- $attrs->{ foo } = 'bar' unless defined $attrs->{ foo };
-
- $class->next::method( $attrs );
+ my ( $class, $attrs ) = @_;
+
+ $attrs->{foo} = 'bar' unless defined $attrs->{foo};
+
+ $class->next::method($attrs);
}
=head2 Stringification
-Deploy the standard stringification technique by using the C<overload> module. Replace
-C<foo> with the column/method of your choice.
+Employ the standard stringification technique by using the C<overload>
+module. Replace C<foo> with the column/method of your choice.
use overload '""' => 'foo', fallback => 1;
-=back
+=cut
=head1 NAME
-DBIx::Class::Manual::FAQ - Frequently Asked Questions
+DBIx::Class::Manual::FAQ - Frequently asked questions
-=head1 General
+=head1 GENERAL
=head2 What is the point of this module? Is it a fork of Class::DBI?
-This is an alternative to Class::DBI, intended to provide greater
+This is an alternative to L<Class::DBI>, intended to provide greater
functionality and simplicity.
-It is inspired by the Class::DBI framework, and meant to support
+It is inspired by the L<Class::DBI> framework, and meant to support
compability with it, while restructuring the internals and making it
-possible to support some new features like self-joins, distinct, group
-bys and more.
-
-=head2 Who's the intended audience for this module?
+possible to support some new features like self-joins, C<DISTINCT>,
+C<GROUP BY>s and more.
=head2 What databases does it support?
merit a full justification on the mailing list and a CPAN developer
release for people to test against.
-=head2 What's planned in the future?
-
=head2 Where can I go for support?
- Mailing list: http://lists.rawmode.org/mailman/listinfo/dbix-class/
+ Mailing list: http://lists.rawmode.org/mailman/listinfo/dbix-class/
- SVN: http://dev.catalyst.perl.org/repos/bast/trunk/DBIx-Class/
+ SVN: http://dev.catalyst.perl.org/repos/bast/trunk/DBIx-Class/
- Wiki: http://dbix-class.shadowcatsystems.co.uk/
+ Wiki: http://dbix-class.shadowcatsystems.co.uk/
- IRC: irc.perl.org#dbix-class
+ IRC: irc.perl.org#dbix-class
-=head1 PostgresQL Specific Problems
+=head1 POSTGRESQL-SPECIFIC PROBLEMS
-=head2 Can't get last insert id - inserts with serial primary keys fail
+=head2 Can't get last insert ID; inserts with serial primary keys fail
-Older DBI and DBD::Pg versions fail to correctly handle
-C<last_insert_id> correctly, causing code that uses auto incrementing
-primary key columns to fail with a message such as:-
+Older L<DBI> and L<DBD::Pg> versions do not handle C<last_insert_id>
+correctly, causing code that uses auto-incrementing primary key
+columns to fail with a message such as:
- Can't get last insert id at /.../DBIx/Class/Row.pm line 95
+ Can't get last insert id at /.../DBIx/Class/Row.pm line 95
In particular the RHEL 4 and FC3 Linux distributions both ship with
-combinations of DBI and DBD::Pg modules that do not work correctly.
+combinations of L<DBI> and L<DBD::Pg> modules that do not work
+correctly.
-DBI version 1.50 and DBD::Pg 1.43 are known to work.
+L<DBI> version 1.50 and L<DBD::Pg> 1.43 are known to work.
-=cut
+=head1 SEE ALSO
+
+=over 4
+=item L<DBIx::Class::Manual::Intro>
+
+=back
+
+=cut
DBIx::Class::Manual::Intro - Introduction to DBIx::Class
-=head1 Introduction.
+=head1 INTRODUCTION
-So, you are bored with SQL, and want a native perl interface for your classes?
-Or you've been doing this for a while with L<Class::DBI>, and think there's
-a better way? You've come to the right place. Let's look at how you can set
-and use your first native DBIx::Class tree.
+So, you are bored with SQL, and want a native Perl interface for your
+database? Or you've been doing this for a while with L<Class::DBI>,
+and think there's a better way? You've come to the right place. Let's
+look at how you can set and use your first native L<DBIx::Class> tree.
-First we'll see how you can set up your classes yourself. If you want them
-to be auto-discovered, just skip to the next section, which shows you how
-to use DBIx::Class::Loader.
+First we'll see how you can set up your classes yourself. If you want
+them to be auto-discovered, just skip to the next section, which shows
+you how to use L<DBIx::Class::Loader>.
=head2 Setting it up manually
First, you'll need a base class. It should inherit from DBIx::Class
like this:
- package MyApp::DB
- use base qw/DBIx::Class/;
+ package MyApp::DB;
+ use base qw/DBIx::Class/;
-You will also want to load some of L<DBIx::Class>'s components.
-L<DBIx::Class::Core> provides a good basic set. In addition you'll
+You will also want to load some of L<DBIx::Class>'s components.
+L<DBIx::Class::Core> provides a good basic set. In addition you'll
have to use either L<DBIx::Class::Schema> or L<DBIx::Class::DB> We'll
-use DB in this introduction, since it involves less magic. Schema is
-mostly useful if you want to use multiple database connections.
+use C<DB> in this introduction, since it involves less magic.
+L<Schema> is mostly useful if you want to use multiple database
+connections.
- __PACKAGE__->load_components(qw/Core DB/);
+ __PACKAGE__->load_components(qw/Core DB/);
If you want serial/auto-incremental primary keys, you'll need to add
-the apropriate component for your db as well, for example. The
-PK::Auto::* modules help L<DBIx::Class> keep up with newly generated
-keys in auto increment database fields.
+the apropriate component for your db as well, for example. The
+L<DBIx::Class::PK::Auto> modules help L<DBIx::Class> keep up with
+newly generated keys in auto increment database fields.
- __PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
+ __PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
Once you've loaded the components, it's time to set up your connection:
- __PACKAGE__->connection('dbi:SQLite:/home/me/myapp/my.db');
+ __PACKAGE__->connection('dbi:SQLite:/home/me/myapp/my.db');
-This method is similar to the normal L<DBI>, and can take user/pass/dbi
-attribute hash as well as the dsn.
+This method is similar to the normal L<DBI>, and can take username,
+password, and L<DBI> attribute hash as well as the DSN.
With that out of the way, we can define our first table class:
- package MyApp::DB::Album;
-
- use base qw/MyApp::DB/;
+ package MyApp::DB::Album;
+ use base qw/MyApp::DB/;
Then we specify which table it uses,
- __PACKAGE__->table('album');
+ __PACKAGE__->table('album');
and specify which columns it has.
- __PACKAGE__->add_columns(qw/albumID artist title label year/);
+ __PACKAGE__->add_columns(qw/albumID artist title label year/);
-This will automatically create accessors for each of the columns, so that
-you can read/update the values in rows you've retrieved.
+This will automatically create accessors for each of the columns, so
+that you can read/update the values in rows you've retrieved.
Also, you need to tell it which column is the primary key:
- __PACKAGE__->set_primary_key('albumID');
+ __PACKAGE__->set_primary_key('albumID');
If you have multiple primary keys, just pass a list instead.
-That's pretty much all you need for a basic setup. If you have more advanced
-needs like using more than 1 database connections for the same class, see
-L<DBIx::Class::Schema>.
+That's pretty much all you need for a basic setup. If you have more
+advanced needs like using more than one database connection for the
+same class, see L<DBIx::Class::Schema>.
-=head2 Using L<DBIx::Class::Loader>.
+=head2 Using L<DBIx::Class::Loader>
-This is an additional class, and not part of the DBIx::Class distribution.
-Like L<Class::DBI::Loader>, it inspects your database, and automatically
-creates classes for all the tables in your database. Here's a simple setup:
+This is an additional class, and not part of the L<DBIx::Class>
+distribution. Like L<Class::DBI::Loader>, it inspects your database,
+and automatically creates classes for all the tables in your
+database. Here's a simple setup:
- package MyApp::DB;
-
- use DBIx::Class::Loader;
+ package MyApp::DB;
+ use DBIx::Class::Loader;
+
+ my $loader = DBIx::Class::Loader->new(
+ dsn => 'dbi:SQLite:/home/me/myapp/my.db',
+ namespace => 'MyApp::DB'
+ );
- my $loader = DBIx::Class::Loader->new(
- dsn => 'dbi:SQLite:/home/me/myapp/my.db',
- namespace => 'MyApp::DB');
- 1;
+ 1;
-This should be equivalent to the manual in the section above.
-L<DBIx::Class::Loader> takes lots of other options. For more information,
-consult the reference documentation.
+This should be equivalent to the manual in the section above.
+L<DBIx::Class::Loader> takes lots of other options. For more
+information, consult its documentation.
-=head2 Basic Usage
+=head2 Basic usage
-Once you've defined the basic classes, you can start interacting with your
-database. The simplest way to get a column is by primary key:
+Once you've defined the basic classes, you can start interacting with
+your database. The simplest way to get a column is by primary key:
- $albumID = 14;
- $album = MyApp::DB::Album->find($albumID);
+ my $albumID = 14;
+ my $album = MyApp::DB::Album->find($albumID);
-This will run a select with albumID=14 in the WHERE clause, and return an instance
-of MyApp::DB::Artist that represents this row. Once you have that row, you can
-access and update columns
+This will run a select with C<albumID = 14> in the C<WHERE> clause,
+and return an instance of C<MyApp::DB::Artist> that represents this
+row. Once you have that row, you can access and update columns:
- $album->title('Physical Graffiti');
- $title = $album->title; # $title holds 'Physical Graffiti'
+ $album->title('Physical Graffiti');
+ my $title = $album->title; # $title holds 'Physical Graffiti'
-or if you prefer, you can use the set_column/get_column accessors instead
-of the autogenerated accessors based on your column names.
+If you prefer, you can use the C<set_column> and C<get_column>
+accessors instead:
-Just like with L<Class::DBI>, you do an 'update' to commit your changes
-to the database:
+ $album->set_column('title', 'Presence');
+ $title = $album->get_column('title');
- $album->update;
+Just like with L<Class::DBI>, you do an C<update> to commit your
+changes to the database:
+
+ $album->update;
If needed, you can drop your local changes instead like this:
- $album->discard_changes if $album->is_changed;
+ $album->discard_changes if $album->is_changed;
-As you can see, is_changed allows you to check if there are local changes to
-your object.
+As you can see, C<is_changed> allows you to check if there are local
+changes to your object.
-=head2 Adding and removing rows.
+=head2 Adding and removing rows
-To create a new record in the database, you can use the 'create'
-method from L<DBIx::Class::Row>. It returns a L<DBIx::Class::ResultSet>
-object that can be used to access the data in the new record.
+To create a new record in the database, you can use the C<create>
+method from L<DBIx::Class::Row>. It returns a
+L<DBIx::Class::ResultSet> object that can be used to access the data
+in the new record.
- $new_album = MyApp::DB::Album->create({
- title => 'Wish You Were Here',
- artist => 'Pink Floyd'
- });
+ my $new_album = MyApp::DB::Album->create({
+ title => 'Wish You Were Here',
+ artist => 'Pink Floyd'
+ });
Now you can add data to the new record:
- $new_album->label('Capitol');
- $new_album->year('1975');
+ $new_album->label('Capitol');
+ $new_album->year('1975');
-likewise, you can remove if from the database like this:
+Likewise, you can remove if from the database like this:
- $new_album->delete();
+ $new_album->delete;
-or even without retrieving first. This operation takes the same kind of
-arguments as a search.
+or even without retrieving first. This operation takes the same kind
+of arguments as a search.
- MyApp::DB::Album->delete({ artist => 'Falco' });
+ MyApp::DB::Album->delete({ artist => 'Falco' });
-=head2 Finding your objects.
+=head2 Finding your objects
-DBIx::Class provides a few different ways to retrieve data from your database.
-The simplest looks something like this:
+L<DBIx::Class> provides a few different ways to retrieve data from
+your database. The simplest looks something like this:
- $album = MyApp::DB::Album->search( artist => 'Santana' );
+ my $album = MyApp::DB::Album->search( artist => 'Santana' );
-note that all the search methods return a L<DBIx::Class::ResultSet> object
-in scalar context or a list containing all the records in list context.
+Note that all the search methods return a L<DBIx::Class::ResultSet>
+object in scalar context or a list containing all the records in list
+context.
-We also provide a handy shortcut for doing a "like" search:
+We also provide a handy shortcut for doing a C<LIKE> search:
- $album = MyApp::DB::Album->search_like( artist => 'Jimi%');
+ my $album = MyApp::DB::Album->search_like( artist => 'Jimi%' );
-Or you can provide your own handmade WHERE clause, like
+Or you can provide your own handmade C<WHERE> clause, like:
- $album = MyApp::DB::Album->search_literal('artist=?','Peter Frampton');
+ my $album = MyApp::DB::Album->search_literal( 'artist = ?', 'Peter Frampton' );
+
+The preferred way to generate complex queries is to provide a
+L<SQL::Abstract> construct to C<search>:
+
+ my $album = MyApp::DB::Album->search({
+ artist => { '!=', 'Janis Joplin' },
+ year => { '<' => 1980 },
+ id => [ 1, 14, 15, 65, 43 ]
+ });
+
+For more examples of complex searches, see
+L<DBIx::Class::Manual::Cookbook>.
+
+The search can also be modified by passing another hash with
+attributes:
+
+ my $album = MyApp::DB::Album->search(
+ { artist => 'Bob Marley' },
+ { page => 1, rows => 2, order_by => 'year' }
+ );
+
+For a complete overview of the available attributes, see
+L<DBIx::Class::ResultSet/ATTRIBUTES>.
-The other way to provide more complex queries, is to provide a
-L<SQL::Abstract> construct to search:
+=head1 SEE ALSO
- $album = MyApp::DB::Album->search({
- artist => { '!=', 'Janis Joplin' },
- year => { '<' => 1980 },
- id => [ 1, 14, 15, 65, 43 ]
- });
+=over 4
-The search can also be modifyed by passing another hash with attributes:
+=item * L<DBIx::Class::Manual::Cookbook>
- $album = MyApp::DB::Album->search(
- { artist => 'Bob Marley' },
- { page => 1, rows => 2, order_by => 'year' }
- );
+=item * L<DBIx::Class::Manual::FAQ>
-For a complete overview over the available attributes, see
-L<DBIx::Class::ResultSet>
+=back
=cut