This is not as easy as it could be, but it's possible. Here's an example to
illustrate:
- package Base;
+ # Set up inherited connection information
+ package MyApp::DBIC;
- use base qw/DBIx::Class/;
+ use base qw/DBIx::Class/;
- __PACKAGE__->load_components(qw/Core DB/);
- __PACKAGE__->connection(...);
+ __PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
+ __PACKAGE__->connection(...);
- package Left;
+ # Set up a class for the 'authors' table
+ package MyApp::DBIC::Author;
+ use base qw/MyApp::DBIC/;
- use base qw/Base/;
+ __PACKAGE__->table('authors');
+ __PACKAGE__->add_columns(qw/authID first_name last_name/);
+ __PACKAGE__->set_primary_key(qw/authID/);
- __PACKAGE__->table('left');
- __PACKAGE__->add_columns(qw/id left_stuff/);
- __PACKAGE__->set_primary_key(qw/id/);
- __PACKAGE__->has_many('mid' => 'Mid');
+ # Define relationship to the link table
+ __PACKAGE__->has_many('b2a' => 'MyApp::DBIC::Book2Author', 'authID');
- sub right {
- my ($self) = @_;
- return Right->search(
- { 'left.id' => $self->id },
- { join => { 'mid' => 'left' }});
- }
+ # Create the accessor for books from the ::Author class
+ sub books {
+ my ($self) = @_;
+ return MyApp::DBIC::Book->search(
+ { 'b2a.authID' => $self->authID }, { join => 'b2a' }
+ );
+ # '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.
+ }
- package Mid;
+ # define the link table class
+ package MyApp::DBIC::Book2Author;
- use base qw/Base/;
+ use base qw/MyApp::DBIC/;
- __PACKAGE__->table('mid');
- __PACKAGE__->add_columns(qw/left right/);
- __PACKAGE__->set_primary_key(qw/left right/);
+ __PACKAGE__->table('book2author');
+ __PACKAGE__->add_columns(qw/bookID authID/);
+ __PACKAGE__->set_primary_key(qw/bookID authID/);
- __PACKAGE__->belongs_to('left' => 'Left');
- __PACKAGE__->belongs_to('right' => 'Right');
+ __PACKAGE__->belongs_to('authID' => 'MyApp::DBIC::Author');
+ __PACKAGE__->belongs_to('bookID' => 'MyApp::DBIC::Book');
- package Right;
+ package MyApp::DBIC::Book;
- use base qw/Base/;
+ use base qw/MyApp::DBIC/;
- __PACKAGE__->table('right');
- __PACKAGE__->add_columns(qw/id right_stuff/);
- __PACKAGE__->set_primary_key(qw/id/);
- __PACKAGE__->has_many('mid' => 'Mid');
+ __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 left {
- my ($self) = @_;
- return Left->search(
- { 'right.id' => $self->id },
- { join => { 'mid' => 'right' });
- }
+ sub authors {
+ my ($self) = @_;
+ return MyApp::DBIC::Author->search(
+ { 'b2a.bookID' => $self->bookID }, # WHERE clause
+ { join => 'b2a' }); # Join condition
+ }
+
+ # 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
=item Advanced Exception handling
__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 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.
__PACKAGE__->load_components(qw/PK::Auto::SQLite Core DB/);
With that out of the way, we can define our first table class:
- package MyApp::DB::Frob
+ package MyApp::DB::Album;
use base qw/MyApp::DB/;
Then we specify which table it uses,
- __PACKAGE__->table('frob');
+ __PACKAGE__->table('album');
and specify which columns it has.
- __PACKAGE__->add_columns(qw/id foo bar/);
+ __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.
Also, you need to tell it which column is the primary key:
- __PACKAGE__->set_primary_key('id');
+ __PACKAGE__->set_primary_key('albumID');
If you have multiple primary keys, just pass a list instead.
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;
This should be equivalent to the manual in the section above.
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:
- my $frob=MyApp::DB::Frob->find(14);
+ $albumID = 14;
+ $album = MyApp::DB::Album->find($albumID);
-This will run a select with id=14 in the WHERE clause, and return an instance
-of MyApp::DB::Frob that represents this row. Once you have that row, you can
+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
- my $val=$frob->bar;
- $frob->bar(14);
+ $album->title('Physical Graffiti');
+ $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.
Just like with L<Class::DBI>, you do an 'update' to commit your changes
to the database:
- $frob->update;
+ $album->update;
If needed, you can drop your local changes instead like this:
- $frob->discard_changes if $frob->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.
=head2 Adding and removing rows.
-To make a new row, and put it into the database, you can use the 'create'
-method from L<DBIx::Class::Row>
+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.
- my $new_thingie=MyApp::DB::Frob->create({
- foo=>'homer',
- bar=>'bart' });
+ $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');
likewise, you can remove if from the database like this:
- $new_thingie->delete();
+ $new_album->delete();
or even without retrieving first. This operation takes the same kind of
arguments as a search.
- MyApp::DB::Frob->delete({foo=>'bart'});
+ MyApp::DB::Album->delete({ artist => 'Falco' });
=head2 Finding your objects.
DBIx::Class provides a few different ways to retrieve data from your database.
The simplest looks something like this:
- $rs=MyApp::DB::Frob->search(foo=>'bart');
+ $album = MyApp::DB::Album->search( artist => 'Santana' );
-note that all the search methods return a recordset in scalar context or
-a list containing all the elements 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 "like" search:
- $rs=MyApp::DB::Frob->search_like(foo=>'bar%');
+ $album = MyApp::DB::Album->search_like( artist => 'Jimi%');
Or you can provide your own handmade WHERE clause, like
- $rs=MyApp::DB::Frob->search_literal('foo=?','bart');
+ $album = MyApp::DB::Album->search_literal('artist=?','Peter Frampton');
The other way to provide more complex queries, is to provide a
L<SQL::Abstract> construct to search:
- $rs=MyApp::DB::Frob->search({
- bar=>{'>' => 10 },
- foo=>{'!=','bart'},
- id => [1,14,15,65,43]
+ $album = MyApp::DB::Album->search({
+ artist => { '!=', 'Janis Joplin' },
+ year => { '<' => 1980 },
+ id => [ 1, 14, 15, 65, 43 ]
});
The search can also be modifyed by passing another hash with attributes:
- $rs=MyApp::DB::Frob->search( {foo=>'bart'},
- { page=>1, rows=>2, order_by=>'bar' } );
+ $album = MyApp::DB::Album->search(
+ { artist => 'Bob Marley' },
+ { page => 1, rows => 2, order_by => 'year' }
+ );
For a complete overview over the available attributes, see
L<DBIx::Class::ResultSet>