Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

My DBI application uses these tables:

books (columns: productid title pages price format)
authors (columns: authorid name)
titlesauthors (columns: productid authorid)

Using Class::DBI, I have created classes for these tables, but I cannot figure out from the docs how to set up the correct mapping between books and authors.
I want to do something like

@authors = $book->authors

The author of Class::DBI::Join has deleted that module from CPAN and suggests that Class::DBI itself can do the join, but I don't see how.

Thanks for any help.
Arun

Replies are listed 'Best First'.
Re: Joins with Class::DBI
by cees (Curate) on Jul 19, 2003 at 16:15 UTC

    Check out the section on the has_many and has_a methods. You will want to add something like the following to your classes:

    # To your authors class __PACKAGE__->has_many('books', 'My::DB::Books' => book_id); # To your books class __PACKAGE__->has_a('author_id', 'My::DB::Authors');

    Then in your code you can use:

    my $author = My::DB::Authors->retrieve($author_id); # method add_to_books is created for you by has_many $author->add_to_books({ col1 => value1, col2 => value2, ... }); # author_id will be filled in automatically my $books = $author->books; while (my $book = $books->next) { ... }

    - Cees

      Not quite. This would be correct if there were a one-to-many relationship between authors and books (ie if each book was allowed only one author), but the OP has a many-to-many relationship there - presumably on the grounds that some books have several authors - and, like everyone, is wondering how to make the joining table invisible. The short answer is that s/he does have to create a My::DB::AuthorBook joining class, but s/he will probably never need to access it directly. It's in the pod under 'mapping', a subheading of 'relationships'.

Re: Joins with Class::DBI
by thpfft (Chaplain) on Jul 19, 2003 at 23:01 UTC

    the old way of doing this was to set up an AuthorBook class that had_a book and had_a author, and then use the nearly ubiquitous idiom:

    Package Author; Author->has_many('_book_links', 'AuthorBook', 'author'); sub books { return map { $_->book } shift->_book_links; }

    but as of 0.91ish, you can achieve exactly the same thing with:

    Package Author; Author->has_many('books', [ AuthorBook => 'book' ], 'author');

    The syntax is getting rather arbitrary (I'd really like to see named parameters there), and you still have to create the nearly-empty AuthorBook class, but that's kind of a good thing - there will probably be methods you want to add to it one day - and at least this way the relationships are defined where it makes most sense to look for them.

    ps. the author of Class::DBI::Join was Michael Schwern, also the original author of Class::DBI and the main reason why it's so simple, powerful, horrible inside and reliant on strange non-standard pragmas that Make OOP More Fun (to Schwern). All will kneel.