DBIx-DataModel
view release on metacpan or search on metacpan
lib/DBIx/DataModel/Doc/Cookbook.pod view on Meta::CPAN
$self->{$key_column} = $random_key;
eval {$self->_rawInsert; 1}
and return $random_key; # SUCCESS
# if duplication error, try again; otherwise die
last unless $DBI::errstr =~ $DUPLICATE_ERROR;
}
croak "cannot generate a random key for $class: $@";
}
foreach my $class (@tables_with_random_keys) {
define_method(
class => $schema->metadm->table($class)->class,
name => '_singleInsert',
body => \&insert_with_random_key,
);
}
=head2 Cascaded operations
Some database systems support cascaded operations : for example
a constraint definition with a clause like C<ON DELETE CASCADE>
will automatically delete child rows (rows containing foreign keys)
when the parent row (the row containing the primary key) is deleted.
C<DBIx::DataModel> does not know about such cascaded operations in the
database; but it can perform some cascaded operations at the ORM level,
when tables are associated through a
L<composition|DBIx::DataModel::Doc::Glossary/"composition">.
In that case, the C<insert()> method can accept a data tree as argument,
and will automatically perform recursive inserts in the children tables;
an example is given in the
L<quickstart tutorial|DBIx::DataModel::Doc::Quickstart/"Cascaded inserts">.
Cascaded deletes are also supported :
my $bach = HR->table('Employee')->fetch($bach_id);
$bach->expand('activities');
$bach->delete; # deletes the Employee together with its Activities
The C<expand> operations retrieve related records and add them
into a tree in memory. Then C<delete> removes from the database
all records found in the tree.
Observe that this is not a "true" cascaded
delete, because the client code is responsible for fetching the
related records first.
=head2 Timestamp validation
Suppose we want to sure that the record was not touched between the time
it was presented to the user in a display form and the time
the user wants to update or delete that record.
In order to do this, we will suppose that every record in every
table has a timestamp field C<TS_MODIF>, updated automatically by
a trigger within the database. When defining the schema, we
register an I<auto_update> callback on that column; such callbacks
are called automatically both on C<update()> and C<insert()> calls :
DBIx::DataModel->define_schema(
class => 'My::Schema',
auto_update_columns => {TS_MODIF => \&_check_time_stamp},
);
The body of the callback looks like this :
sub _check_time_stamp {
my ($record, $table, $where) = @_;
if ($where) { # this is an update, not an insert
my $displayed_timestamp = delete $record->{TS_MODIF};
my $db_record = $record->schema->table($table)->select(
-columns => 'TS_MODIF',
-where => $where,
-for => 'update', # optional, depends on your RDBMS
-result_as => 'firstrow',
)
or croak "fetch timestamp: could not find record "
. join(" / ", %$where);
my $db_timestamp = $db_record->{TS_MODIF};
$db_timestamp == $displayed_timestamp
or croak "record in $table was modified by somebody else; please "
. "refresh your screen and try again";
}
}
=head1 DATA CONVERSION
=head2 JSON
use JSON;
my $json_converter = JSON->new->convert_blessed(1);
my $json_text = $json_converter->encode($data_row);
By default, the L<JSON> module refuses to convert any object into JSON;
however, the L<JSON/convert_blessed> option will accept to convert objects
provided they possess a C<TO_JSON> method. Such a method is implemented in
the L<DBIx::DataModel::Source/DBIx::DataModel::Source> class, so
any data row can be converted into JSON.
( run in 1.184 second using v1.01-cache-2.11-cpan-39bf76dae61 )