Class-DBI

 view release on metacpan or  search on metacpan

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

objects and the values are the initial settings of those fields.

  my $cd = Music::CD->insert({ 
    cdid   => 1,
    artist => $artist,
    title  => 'October',
    year   => 1980,
  });

If the table has a single primary key column and that column value
is not defined in %data, insert() will assume it is to be generated.
If a sequence() has been specified for this Class, it will use that.
Otherwise, it will assume the primary key can be generated by
AUTO_INCREMENT and attempt to use that.

The C<before_create> trigger is invoked directly after storing the
supplied values into the new object and before inserting the record
into the database. The object stored in $self may not have all the
functionality of the final object after_creation, particularly if the
database is going to be providing the primary key value.

For tables with multi-column primary keys you need to supply all
the key values, either in the arguments to the insert() method, or
by setting the values in a C<before_create> trigger.

If the class has declared relationships with foreign classes via
has_a(), you can pass an object to insert() for the value of that key.
Class::DBI will Do The Right Thing.

After the new record has been inserted into the database the data
for non-primary key columns is discarded from the object. If those
columns are accessed again they'll simply be fetched as needed.
This ensures that the data in the application is consistent with
what the database I<actually> stored.

The C<after_create> trigger is invoked after the database insert
has executed.

=head2 find_or_create

  my $cd = Music::CD->find_or_create({ artist => 'U2', title => 'Boy' });

This checks if a CD can be found to match the information passed, and
if not inserts it. 

=head2 delete

  $obj->delete;
  Music::CD->search(year => 1980, title => 'Greatest %')->delete_all;

Deletes this object from the database and from memory. If you have set up
any relationships using C<has_many> or C<might_have>, this will delete
the foreign elements also, recursively (cascading delete).  $obj is no
longer usable after this call.

Multiple objects can be deleted by calling delete_all on the Iterator
returned from a search. Each object found will be deleted in turn,
so cascading delete and other triggers will be honoured.

The C<before_delete> trigger is when an object instance is about to be
deleted. It is invoked before any cascaded deletes.  The C<after_delete>
trigger is invoked after the record has been deleted from the database
and just before the contents in memory are discarded.

=head1 RETRIEVING OBJECTS

Class::DBI provides a few very simple search methods. 

It is not the goal of Class::DBI to replace the need for using SQL. Users
are expected to write their own searches for more complex cases.

L<Class::DBI::AbstractSearch>, available on CPAN, provides a much more
complex search interface than Class::DBI provides itself.

=head2 retrieve

  $obj = Class->retrieve( $id );
  $obj = Class->retrieve( %key_values );

Given key values it will retrieve the object with that key from the
database.  For tables with a single column primary key a single
parameter can be used, otherwise a hash of key-name key-value pairs
must be given.

  my $cd = Music::CD->retrieve(1) or die "No such cd";

=head2 retrieve_all

  my @objs = Class->retrieve_all;
  my $iterator = Class->retrieve_all;

Retrieves objects for all rows in the database. This is probably a
bad idea if your table is big, unless you use the iterator version.

=head2 search

  @objs = Class->search(column1 => $value, column2 => $value ...);

This is a simple search for all objects where the columns specified are
equal to the values specified e.g.:

  @cds = Music::CD->search(year => 1990);
  @cds = Music::CD->search(title => "Greatest Hits", year => 1990);

You may also specify the sort order of the results by adding a final
hash of arguments with the key 'order_by':

  @cds = Music::CD->search(year => 1990, { order_by=>'artist' });

This is passed through 'as is', enabling order_by clauses such
as 'year DESC, title'.

=head2 search_like

  @objs = Class->search_like(column1 => $like_pattern, ....);

This is a simple search for all objects where the columns specified are
like the values specified.  $like_pattern is a pattern given in SQL LIKE
predicate syntax.  '%' means "any zero or more characters", '_' means
"any single character". 

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

    position => 6,
    title    => 'Tomorrow',
  });

When setting up the relationship the foreign class's has_a() declarations
are examined to discover which of its columns reference our class. (Note
that because this happens at compile time, if the foreign class is defined
in the same file, the class with the has_a() must be defined earlier than
the class with the has_many(). If the classes are in different files,
Class::DBI should usually be able to do the right things, as long as all
classes inherit Class::DBI before 'use'ing any other classes.)

If the foreign class has no has_a() declarations linking to this class,
it is assumed that the foreign key in that class is named after the
moniker() of this class.

If this is not true you can pass an additional third argument to
the has_many() declaration stating which column of the foreign class
is the foreign key to this class.

=head3 Limiting

  Music::Artist->has_many(cds => 'Music::CD');
  my @cds = $artist->cds(year => 1980);

When calling the method created by has_many, you can also supply any
additional key/value pairs for restricting the search. The above example
will only return the CDs with a year of 1980.

=head3 Ordering

  Music::CD->has_many(tracks => 'Music::Track', { order_by => 'playorder' });

has_many takes an optional final hashref of options. If an 'order_by'
option is set, its value will be set in an ORDER BY clause in the SQL
issued. This is passed through 'as is', enabling order_by clauses such
as 'length DESC, position'.

=head3 Mapping

  Music::CD->has_many(styles => [ 'Music::StyleRef' => 'style' ]);

If the second argument to has_many is turned into a listref of the
Classname and an additional method, then that method will be called in
turn on each of the objects being returned.

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/);



( run in 0.404 second using v1.01-cache-2.11-cpan-2398b32b56e )