Class-DBI

 view release on metacpan or  search on metacpan

lib/Class/DBI.pm  view on Meta::CPAN


The above is exactly equivalent to:

  Music::CD->has_many(_style_refs => 'Music::StyleRef');

  sub styles { 
    my $self = shift;
    return map $_->style, $self->_style_refs;
  }

For an example of where this is useful see L<"MANY TO MANY RELATIONSHIPS">
below.

=head3 Cascading Delete
    
  Music::Artist->has_many(cds => 'Music::CD', { cascade => 'Fail' });

It is also possible to control what happens to the 'child' objects when
the 'parent' object is deleted. By default this is set to 'Delete' - so,
for example, when you delete an artist, you also delete all their CDs,
leaving no orphaned records. However you could also set this to 'None',
which would leave all those orphaned records (although this generally
isn't a good idea), or 'Fail', which will throw an exception when you
try to delete an artist that still has any CDs.

You can also write your own Cascade strategies by supplying a Class
Name here.

For example you could write a Class::DBI::Cascade::Plugin::Nullify
which would set all related foreign keys to be NULL, and plug it into
your relationship:

  Music::Artist->has_many(cds => 'Music::CD', { 
    cascade => 'Class::DBI::Cascade::Plugin::Nullify' 
  });

=head2 might_have

  Music::CD->might_have(method_name => Class => (@fields_to_import));

  Music::CD->might_have(liner_notes => LinerNotes => qw/notes/);

  my $liner_notes_object = $cd->liner_notes;
  my $notes = $cd->notes; # equivalent to $cd->liner_notes->notes;

might_have() is similar to has_many() for relationships that can have
at most one associated objects. For example, if you have a CD database
to which you want to add liner notes information, you might not want
to add a 'liner_notes' column to your main CD table even though there
is no multiplicity of relationship involved (each CD has at most one
'liner notes' field). So, you create another table with the same primary
key as this one, with which you can cross-reference.

But you don't want to have to keep writing methods to turn the the
'list' of liner_notes objects you'd get back from has_many into the
single object you'd need. So, might_have() does this work for you. It
creates an accessor to fetch the single object back if it exists, and
it also allows you import any of its methods into your namespace. So,
in the example above, the LinerNotes class can be mostly invisible -
you can just call $cd->notes and it will call the notes method on the
correct LinerNotes object transparently for you.

Making sure you don't have namespace clashes is up to you, as is correctly
creating the objects, but this may be made simpler in later versions.
(Particularly if someone asks for this!)

=head2 Notes

has_a(), might_have() and has_many() check that the relevant class has
already been loaded. If it hasn't then they try to load the module of
the same name using require.  If the require fails because it can't
find the module then it will assume it's not a simple require (i.e.,
Foreign::Class isn't in Foreign/Class.pm) and that you will take care
of it and ignore the warning. Any other error, such as a syntax error,
triggers an exception.

NOTE: The two classes in a relationship do not have to be in the same
database, on the same machine, or even in the same type of database! It
is quite acceptable for a table in a MySQL database to be connected to
a different table in an Oracle database, and for cascading delete etc
to work across these. This should assist greatly if you need to migrate
a database gradually.

=head1 MANY TO MANY RELATIONSHIPS

Class::DBI does not currently support Many to Many relationships, per se.
However, by combining the relationships that already exist it is possible
to set these up.

Consider the case of Films and Actors, with a linking Role table with a
multi-column Primary Key. First of all set up the Role class:

  Role->table('role');
  Role->columns(Primary => qw/film actor/);
  Role->has_a(film => 'Film');
  Role->has_a(actor => 'Actor');

Then, set up the Film and Actor classes to use this linking table:

  Film->table('film');
  Film->columns(All => qw/id title rating/);
  Film->has_many(stars => [ Role => 'actor' ]);

  Actor->table('actor');
  Actor->columns(All => qw/id name/);
  Actor->has_many(films => [ Role => 'film' ]);

In each case the 'mapping method' variation of has_many() is used to 
call the lookup method on the Role object returned. As these methods are
the 'has_a' relationships on the Role, these will return the actual
Actor and Film objects, providing a cheap many-to-many relationship.

In the case of Film, this is equivalent to the more long-winded:

  Film->has_many(roles => "Role");

  sub actors { 
    my $self = shift;
    return map $_->actor, $self->roles 
  }



( run in 1.606 second using v1.01-cache-2.11-cpan-39bf76dae61 )