=head1 NAME

DBIx::DataModel::Doc::Misc - Other considerations



=head1 DOCUMENTATION CONTEXT

This chapter is part of the C<DBIx::DataModel> manual.

=over

=item * 

L<SYNOPSIS AND DESCRIPTION|DBIx::DataModel>

=item * 

L<DESIGN|DBIx::DataModel::Doc::Design>

=item * 

L<QUICKSTART|DBIx::DataModel::Doc::Quickstart>

=item *

L<REFERENCE|DBIx::DataModel::Doc::Reference>

=item *

MISC

=item *

L<INTERNALS|DBIx::DataModel::Doc::Internals>

=item *

L<GLOSSARY|DBIx::DataModel::Doc::Glossary>

=back


=head1 NAMESPACES, CLASSES, METHODS

C<DBIx::DataModel> automatically generates Perl classes for Schemas,
Tables, Views, Associations. Before doing so, it checks that no Perl
package of the same name already exists in memory.  
A similar check is performed
before adding role methods into classes.

The client code can insert additional methods into the generated
classes : just switch to the package and define your code.  However,
because of the security checks just mentioned, C<DBIx::DataModel> must
create the package B<before> you start adding methods to it, and
therefore the declarations should be inside a BEGIN block :

  BEGIN { # make sure these declarations are immediately executed
    
    DBIx::DataModel->Schema('MySchema') 
      ->Table(Activity   => Activity   => qw/act_id/);
      ...
  }
    
  # now we can safely add new methods
  
  package MySchema::Activity; 
  
  sub activePeriod {
    my $self = shift;
    $self->{d_end} ? "from $self->{d_begin} to $self->{d_end}"
                   : "since $self->{d_begin}";
  }
  
  package main;			# switch back to the 'main' package

See L<perlmod> for an explanation of BEGIN blocks.


=head1 INTERACTION WITH THE DBI LAYER 

=head2 Transactions and error handling

C<DBIx::DataModel> follows the recommendations
of C<DBI> for transactions : it expects the database handle 
to be opened with C<< RaiseError => 1 >> and therefore does not check itself
for C<DBI> errors ; it is up to the client code
to catch the exceptions and deal with errors.

As explained in L<DBI/Transactions>,
C<AutoCommit> should be set off for databases that support transactions;
then atomic operations are enclosed in an C<eval>, followed by either
C<< $dbh->commit() >> (in case of success) or 
C<< $dbh->rollback() >> (in case of failure).
The 
L<doTransaction()|DBIx::DataModel::Doc::Reference/"doTransaction"> 
method does all this for you automatically.

=head3 Calling DBI directly

Maybe you will encounter situations where 
you need to generate SQL yourself (for example because of
clauses specific to your RDBMS), or to interact directly
with the DBI layer. This can be encapsulated in
additional methods incorporated into the classes
generated by C<DBIx::DataModel>.
In those methods, you may want to call 
L<blessFromDB()|DBIx::DataModel::Doc::Reference/"blessFromDB"> 
so that the rows returned by DBI may be seen as
objects from your client program. Here is an example :

  package MyTable; # switch to namespace 'MyTable'
  
  sub fancyMethod {
  
    # call the DBI API
    my $hash = $dbh->selectall_hashref($fancySQL, @keyFields);
  
    # bless results into objects of My::Table
    My::Table->blessFromDB($_) foreach values %$hash;
  
    return $hash;
  }



=head1 SELF-REFERENTIAL ASSOCIATIONS

Associations can be self-referential, i.e. describing tree
structures :

  $schema->Association([qw/OrganisationalUnit parent   1 ou_id       /],
                       [qw/OrganisationalUnit children * parent_ou_id/],

However, when there are several self-referential associations,
we might get into problems : consider

  $schema->Association([qw/Person mother   1 pers_id  /],
                       [qw/Person children * mother_id/])
         ->Association([qw/Person father   1 pers_id  /],
                       [qw/Person children * father_id/]); # BUG: children

This does not work because there are two definitions  of the "children"
role name in the same class "Person".
One solution is to distinguish these
roles, and then write by hand a general "children" role :

  $schema->Association([qw/Person mother         1 pers_id  /],
                       [qw/Person motherChildren * mother_id/])
         ->Association([qw/Person father         1 pers_id  /],
                       [qw/Person fatherChildren * father_id/]);
  
  package MySchema::Person;
  sub children {
    my $self = shift;
    my $id = $self->{pers_id};
    my $sql = "SELECT * FROM Person WHERE mother_id = $id OR father_id = $id";
    my $children = $self->dbh->selectall_arrayref($sql, {Slice => {}});
    MySchema::Person->blessFromDB($_) foreach @$children;
    return $children;
  }

Alternatively, since rolenames C<motherChildren> and C<fatherChildren>
are most probably useless, we might just specify unidirectional
associations : 

  $schema->Association([qw/Person mother  1 pers_id  /],
                       [qw/Person ---     * mother_id/])
         ->Association([qw/Person father  1 pers_id  /],
                       [qw/Person ---     * father_id/]);

And here is a more sophisticated way to define the "children" method,
that will accept additional "where" criteria, like every regular method.

  package MySchema::Person;
  sub children {
    my $self      = shift; # remaining args in @_ will be passed to select()
    my $id        = $self->{pers_id};
    my $statement = Person->createStatement(-where => [mother_id => $id, 
					               father_id => $id]);
    return $statement->select(@_);
  }

This definition forces the join on C<mother_id> or 
C<father_id>, while leaving open the possibility for the caller
to specify additional criteria. For example, all female children 
of a person (either father or mother) can now be retrieved through

  $person->children(-where => {gender => 'F'})

Observe that C<mother_id> and C<father_id> are inside an arrayref
instead of a hashref, so that L<SQL::Abstract> will generate an SQL 'OR'.


