Rose-DB-Object
view release on metacpan or search on metacpan
lib/Rose/DB/Object.pm view on Meta::CPAN
$self->$method($row{$name});
}
# Sneaky init by object replacement
#my $object = (ref $self)->new(db => $self->db);
#
#foreach my $name (@$column_names)
#{
# my $method = $methods->{$name};
# $object->$method($row{$name});
#}
#
#$self = $_[0] = $object;
}
else
{
no warnings;
$self->error("No such " . ref($self) . ' where ' .
join(', ', @key_columns) . ' = ' . join(', ', @key_values));
$self->{'not_found'} = 1;
$self->{STATE_IN_DB()} = 0;
}
};
$error = $@;
}
if($error)
{
$self->error(ref $error ? $error : "load() - $error");
$meta->handle_error($self);
return undef;
}
unless($loaded_ok)
{
my $speculative =
exists $args{'speculative'} ? $args{'speculative'} :
$meta->default_load_speculative;
unless($speculative)
{
$meta->handle_error($self);
}
return 0;
}
$self->{STATE_IN_DB()} = 1;
$self->{LOADED_FROM_DRIVER()} = $db->{'driver'};
$self->{MODIFIED_COLUMNS()} = {};
return $self || 1;
}
sub save
{
my($self, %args) = @_;
my $meta = $self->meta;
my $cascade =
exists $args{'cascade'} ? $args{'cascade'} :
$meta->default_cascade_save;
# Keep trigger-encumbered and cascade code in separate code path
if($self->{ON_SAVE_ATTR_NAME()} || $cascade)
{
my $db = $args{'db'} || $self->db || return 0;
my $ret = $db->begin_work;
$args{'db'} ||= $db;
unless($ret)
{
my $error = $db->error;
$self->error(ref $error ? $error : "Could not begin transaction before saving - $error");
$self->meta->handle_error($self);
return undef;
}
my $started_new_tx = ($ret == IN_TRANSACTION) ? 0 : 1;
my $error;
TRY:
{
local $@;
eval
{
my %did_set;
my %code_args =
map { ($_ => $args{$_}) } grep { exists $args{$_} }
qw(changes_only prepare_cached cascade);
#
# Do pre-save stuff
#
my $todo = $self->{ON_SAVE_ATTR_NAME()}{'pre'};
foreach my $fk_name (keys %{$todo->{'fk'}})
{
my $code = $todo->{'fk'}{$fk_name}{'set'} or next;
my $object = $code->($self, \%code_args);
# Account for objects that evaluate to false to due overloading
unless($object || ref $object)
{
die $self->error;
}
# Track which rows were set so we can avoid deleting
# them later in the "delete on save" code
$did_set{'fk'}{$fk_name}{Rose::DB::Object::Util::row_id($object)} = 1;
}
#
# Do the actual save
#
if(!$args{'insert'} && ($args{'update'} || $self->{STATE_IN_DB()}))
{
$ret = shift->update(@_);
}
else
{
$ret = shift->insert(@_);
}
#
# Do post-save stuff
#
$todo = $self->{ON_SAVE_ATTR_NAME()}{'post'};
# Foreign keys (and some fk-like relationships)
foreach my $fk_name (keys %{$todo->{'fk'}})
{
foreach my $item (@{$todo->{'fk'}{$fk_name}{'delete'} || []})
{
my $code = $item->{'code'};
my $object = $item->{'object'};
# Don't run the code to delete this object if we just set it above
next if($did_set{'fk'}{$fk_name}{Rose::DB::Object::Util::row_id($object)});
$code->($self, \%code_args) or die $self->error;
}
}
if($cascade)
{
foreach my $fk ($meta->foreign_keys)
{
# If this object was just set above, just save changes (there
# should be none) as a way to continue the cascade
local $args{'changes_only'} = 1 if($todo->{'fk'}{$fk->name}{'set'});
my $foreign_object = $fk->object_has_foreign_object($self) || next;
if(Rose::DB::Object::Util::has_modified_columns($foreign_object) ||
Rose::DB::Object::Util::has_modified_children($foreign_object))
{
$Debug && warn "$self - save foreign ", $fk->name, " - $foreign_object\n";
$foreign_object->save(%args);
}
}
}
# Relationships
foreach my $rel_name (keys %{$todo->{'rel'}})
{
my $code;
# Set value(s)
if($code = $todo->{'rel'}{$rel_name}{'set'})
{
$code->($self, \%code_args) or die $self->error;
}
# Delete value(s)
if($code = $todo->{'rel'}{$rel_name}{'delete'})
{
$code->($self, \%code_args) or die $self->error;
}
# Add value(s)
if($code = $todo->{'rel'}{$rel_name}{'add'}{'code'})
{
$code->($self, \%code_args) or die $self->error;
}
}
if($cascade)
{
foreach my $rel ($meta->relationships)
{
# If this object was just set above, just save changes (there
# should be none) as a way to continue the cascade
local $args{'changes_only'} = 1 if($todo->{'rel'}{$rel->name}{'set'});
my $related_objects = $rel->object_has_related_objects($self) || next;
foreach my $related_object (@$related_objects)
{
if(Rose::DB::Object::Util::has_modified_columns($related_object) ||
Rose::DB::Object::Util::has_modified_children($related_object))
{
$Debug && warn "$self - save related ", $rel->name, " - $related_object\n";
$related_object->save(%args);
}
}
}
}
if($started_new_tx)
{
$db->commit or die $db->error;
}
};
$error = $@;
}
delete $self->{ON_SAVE_ATTR_NAME()};
if($error)
{
$self->error($error);
$db->rollback or warn $db->error if($started_new_tx);
$self->meta->handle_error($self);
return 0;
}
$self->{MODIFIED_COLUMNS()} = {};
return $ret;
}
else
{
if(!$args{'insert'} && ($args{'update'} || $self->{STATE_IN_DB()}))
{
return shift->update(@_);
}
return shift->insert(@_);
}
}
sub update
{
my($self, %args) = @_;
my $db = $self->db or return 0;
my $dbh = $self->dbh or return 0;
my $meta = $self->meta;
my $prepare_cached =
lib/Rose/DB/Object.pm view on Meta::CPAN
else
{
$have_pk = 0;
last;
}
}
$i++;
}
$self->{STATE_IN_DB()} = $have_pk;
}
#if($started_new_tx)
#{
# $db->commit or die $db->error;
#}
};
$error = $@;
}
if($error)
{
$self->error(ref $error ? $error : "insert() - $error");
#$db->rollback or warn $db->error if($started_new_tx);
$self->meta->handle_error($self);
return 0;
}
$self->{MODIFIED_COLUMNS()} = {};
return $self || 1;
}
my %CASCADE_VALUES = (delete => 'delete', null => 'null', 1 => 'delete');
sub delete
{
my($self, %args) = @_;
my $meta = $self->meta;
my $prepare_cached =
exists $args{'prepare_cached'} ? $args{'prepare_cached'} :
$meta->dbi_prepare_cached;
local $self->{STATE_SAVING()} = 1;
my @pk_methods = $meta->primary_key_column_accessor_names;
my @pk_values = grep { defined } map { $self->$_() } @pk_methods;
unless(@pk_values == @pk_methods)
{
$self->error("Cannot delete " . ref($self) . " without a primary key (" .
join(', ', @pk_methods) . ')');
$self->meta->handle_error($self);
return 0;
}
# Totally separate code path for cascaded delete
if(my $cascade = $args{'cascade'})
{
unless(exists $CASCADE_VALUES{$cascade})
{
Carp::croak "Illegal value for 'cascade' parameter: '$cascade'. ",
"Valid values are 'delete', 'null', and '1'";
}
$cascade = $CASCADE_VALUES{$cascade};
my $mgr_error_mode = Rose::DB::Object::Manager->error_mode;
my($db, $started_new_tx, $error);
TRY:
{
local $@;
eval
{
$db = $self->db;
my $meta = $self->meta;
my $ret = $db->begin_work;
unless(defined $ret)
{
die 'Could not begin transaction before deleting with cascade - ',
$db->error;
}
$started_new_tx = ($ret == IN_TRANSACTION) ? 0 : 1;
unless($self->{STATE_IN_DB()})
{
$self->load
or die "Could not load in preparation for cascading delete: ",
$self->error;
}
Rose::DB::Object::Manager->error_mode('fatal');
my @one_to_one_rels;
# Process all the rows for each "... to many" relationship
REL: foreach my $relationship ($meta->relationships)
{
my $rel_type = $relationship->type;
if($rel_type eq 'one to many')
{
my $column_map = $relationship->column_map;
my @query;
foreach my $local_column (keys %$column_map)
{
my $foreign_column = $column_map->{$local_column};
my $method = $meta->column_accessor_method_name($local_column);
my $value = $self->$method();
# XXX: Comment this out to allow null keys
next REL unless(defined $value);
push(@query, $foreign_column => $value);
}
if($cascade eq 'delete')
{
Rose::DB::Object::Manager->delete_objects(
db => $db,
object_class => $relationship->class,
where => \@query);
}
elsif($cascade eq 'null')
{
my %set = map { $_ => undef } values(%$column_map);
Rose::DB::Object::Manager->update_objects(
db => $db,
object_class => $relationship->class,
set => \%set,
where => \@query);
}
else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
}
elsif($rel_type eq 'many to many')
{
my $map_class = $relationship->map_class;
my $map_from = $relationship->map_from;
my $map_from_relationship =
$map_class->meta->foreign_key($map_from) ||
$map_class->meta->relationship($map_from) ||
Carp::confess "No foreign key or 'many to one' relationship ",
"named '$map_from' in class $map_class";
my $key_columns = $map_from_relationship->key_columns;
my @query;
# "Local" here means "local to the mapping table"
foreach my $local_column (keys %$key_columns)
{
my $foreign_column = $key_columns->{$local_column};
my $method = $meta->column_accessor_method_name($foreign_column);
my $value = $self->$method();
# XXX: Comment this out to allow null keys
next REL unless(defined $value);
push(@query, $local_column => $value);
}
if($cascade eq 'delete')
{
Rose::DB::Object::Manager->delete_objects(
db => $db,
object_class => $map_class,
where => \@query);
}
elsif($cascade eq 'null')
{
my %set = map { $_ => undef } keys(%$key_columns);
Rose::DB::Object::Manager->update_objects(
db => $db,
object_class => $map_class,
set => \%set,
where => \@query);
}
else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
}
elsif($rel_type eq 'one to one')
{
push(@one_to_one_rels, $relationship);
}
}
# Delete the object itself
my $dbh = $db->dbh or die "Could not get dbh: ", $self->error;
#local $self->{STATE_SAVING()} = 1;
local $dbh->{'RaiseError'} = 1;
# $meta->prepare_delete_options (defunct)
my $sth = $prepare_cached ? $dbh->prepare_cached($meta->delete_sql($db), undef, 3) :
$dbh->prepare($meta->delete_sql($db));
$Debug && warn $meta->delete_sql($db), " - bind params: ", join(', ', @pk_values), "\n";
$sth->execute(@pk_values);
unless($sth->rows > 0)
{
$self->error("Did not delete " . ref($self) . ' where ' .
join(', ', @pk_methods) . ' = ' . join(', ', @pk_values));
}
# Process all rows referred to by "one to one" foreign keys
FK: foreach my $fk ($meta->foreign_keys)
{
next unless($fk->relationship_type eq 'one to one');
my $key_columns = $fk->key_columns;
my @query;
foreach my $local_column (keys %$key_columns)
{
my $foreign_column = $key_columns->{$local_column};
my $method = $meta->column_accessor_method_name($local_column);
my $value = $self->$method();
# XXX: Comment this out to allow null keys
next FK unless(defined $value);
push(@query, $foreign_column => $value);
}
if($cascade eq 'delete')
{
Rose::DB::Object::Manager->delete_objects(
db => $db,
object_class => $fk->class,
where => \@query);
}
elsif($cascade eq 'null')
{
my %set = map { $_ => undef } values(%$key_columns);
Rose::DB::Object::Manager->update_objects(
db => $db,
object_class => $fk->class,
set => \%set,
where => \@query);
}
else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
}
# Process all the rows for each "one to one" relationship
REL: foreach my $relationship (@one_to_one_rels)
{
my $column_map = $relationship->column_map;
my @query;
foreach my $local_column (keys %$column_map)
{
my $foreign_column = $column_map->{$local_column};
my $method = $meta->column_accessor_method_name($local_column);
my $value = $self->$method();
# XXX: Comment this out to allow null keys
next REL unless(defined $value);
push(@query, $foreign_column => $value);
}
if($cascade eq 'delete')
{
Rose::DB::Object::Manager->delete_objects(
db => $db,
object_class => $relationship->class,
where => \@query);
}
elsif($cascade eq 'null')
{
my %set = map { $_ => undef } values(%$column_map);
Rose::DB::Object::Manager->update_objects(
db => $db,
object_class => $relationship->class,
set => \%set,
where => \@query);
}
else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
}
if($started_new_tx)
{
$db->commit or die $db->error;
}
};
$error = $@;
}
if($error)
{
Rose::DB::Object::Manager->error_mode($mgr_error_mode);
$self->error(ref $error ? $error : "delete() with cascade - $error");
$db->rollback if($db && $started_new_tx);
$self->meta->handle_error($self);
return 0;
}
Rose::DB::Object::Manager->error_mode($mgr_error_mode);
$self->{STATE_IN_DB()} = 0;
return 1;
}
else
{
my $db = $self->db or return 0;
my $dbh = $db->dbh or return 0;
my $error;
TRY:
{
local $@;
eval
{
#local $self->{STATE_SAVING()} = 1;
local $dbh->{'RaiseError'} = 1;
# $meta->prepare_delete_options (defunct)
my $sth = $prepare_cached ? $dbh->prepare_cached($meta->delete_sql($db), undef, 3) :
$dbh->prepare($meta->delete_sql($db));
$Debug && warn $meta->delete_sql($db), " - bind params: ", join(', ', @pk_values), "\n";
$sth->execute(@pk_values);
unless($sth->rows > 0)
{
$self->error("Did not delete " . ref($self) . ' where ' .
join(', ', @pk_methods) . ' = ' . join(', ', @pk_values));
}
};
$error = $@;
}
if($error)
{
$self->error(ref $error ? $error : "delete() - $error");
$self->meta->handle_error($self);
return 0;
}
$self->{STATE_IN_DB()} = 0;
return 1;
}
}
our $AUTOLOAD;
sub AUTOLOAD
{
my $self = shift;
lib/Rose/DB/Object.pm view on Meta::CPAN
=head1 CONSTRUCTOR
=over 4
=item B<new PARAMS>
Returns a new L<Rose::DB::Object> constructed according to PARAMS, where PARAMS are name/value pairs. Any object method is a valid parameter name.
=back
=head1 CLASS METHODS
=over 4
=item B<init_db>
Returns the L<Rose::DB>-derived object used to access the database in the absence of an explicit L<db|/db> value. The default implementation simply calls L<Rose::DB-E<gt>new()|Rose::DB/new> with no arguments.
Override this method in your subclass in order to use a different default data source. B<Note:> This method must be callable as both an object method and a class method.
=item B<meta>
Returns the L<Rose::DB::Object::Metadata>-derived object associated with this class. This object describes the database table whose rows are fronted by this class: the name of the table, its columns, unique keys, foreign keys, etc.
See the L<Rose::DB::Object::Metadata> documentation for more information.
=item B<meta_class>
Return the name of the L<Rose::DB::Object::Metadata>-derived class used to store this object's metadata. Subclasses should override this method if they want to use a custom L<Rose::DB::Object::Metadata> subclass. (See the source code for L<Rose::DB...
=back
=head1 OBJECT METHODS
=over 4
=item B<db [DB]>
Get or set the L<Rose::DB> object used to access the database that contains the table whose rows are fronted by the L<Rose::DB::Object>-derived class.
If it does not already exist, this object is created with a simple, argument-less call to C<Rose::DB-E<gt>new()>. To override this default in a subclass, override the L<init_db|/init_db> method and return the L<Rose::DB> to be used as the new defaul...
=item B<init_db>
Returns the L<Rose::DB>-derived object used to access the database in the absence of an explicit L<db|/db> value. The default implementation simply calls L<Rose::DB-E<gt>new()|Rose::DB/new> with no arguments.
Override this method in your subclass in order to use a different default data source. B<Note:> This method must be callable as both an object method and a class method.
=item B<dbh [DBH]>
Get or set the L<DBI> database handle contained in L<db|/db>.
=item B<delete [PARAMS]>
Delete the row represented by the current object. The object must have been previously loaded from the database (or must otherwise have a defined primary key value) in order to be deleted. Returns true if the row was deleted or did not exist, false...
PARAMS are optional name/value pairs. Valid PARAMS are:
=over 4
=item B<cascade TYPE>
Also process related rows. TYPE must be "delete", "null", or "1". The value "1" is an alias for "delete". Passing an illegal TYPE value will cause a fatal error.
For each "one to many" relationship, all of the rows in the foreign ("many") table that reference the current object ("one") will be deleted in "delete" mode, or will have the column(s) that reference the current object set to NULL in "null" mode.
For each "many to many" relationship, all of the rows in the "mapping table" that reference the current object will deleted in "delete" mode, or will have the columns that reference the two tables that the mapping table maps between set to NULL in "n...
For each "one to one" relationship or foreign key with a "one to one" L<relationship type|Rose::DB::Object::Metadata::ForeignKey/relationship_type>, all of the rows in the foreign table that reference the current object will deleted in "delete" mode,...
In all modes, if the L<db|/db> is not currently in a transaction, a new transaction is started. If any part of the cascaded delete fails, the transaction is rolled back.
=item B<prepare_cached BOOL>
If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will delete the object. If omitted, the default value is determined by the L<metadat...
=back
The cascaded delete feature described above plays it safe by only deleting rows that are not referenced by any other rows (according to the metadata provided by each L<Rose::DB::Object>-derived class). I B<strongly recommend> that you implement "cas...
=item B<error>
Returns the text message associated with the last error that occurred.
=item B<insert [PARAMS]>
Insert the current object to the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be inserted, rather than updated. It is recommended that you use the L<save|/save> method i...
PARAMS are optional name/value pairs. Valid PARAMS are:
=over 4
=item B<changes_only BOOL>
If true, then only the columns whose values have been modified will be included in the insert query. Otherwise, all columns will be included. Note that any column that has a L<default|Rose::DB::Object::Metadata::Column/default> value set in its L<c...
If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_insert_changes_only|Rose::DB::Object::Metadata/default_insert_changes_only> class method, which returns false by default.
=item B<prepare_cached BOOL>
If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will insert the object. If omitted, the default value is determined by the L<metadat...
=back
Returns true if the row was inserted successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of t...
=item B<load [PARAMS]>
Load a row from the database table, initializing the object with the values from that row. An object can be loaded based on either a primary key or a unique key.
Returns true if the row was loaded successfully, undef if the row could not be loaded due to an error, or zero (0) if the row does not exist. The true value returned on success will be the object itself. If the object L<overload>s its boolean value...
When loading based on a unique key, unique keys are considered in the order in which they were defined in the L<metadata|/meta> for this class. If the object has defined values for every column in a unique key, then that key is used. If no such key...
PARAMS are optional name/value pairs. Valid PARAMS are:
=over 4
=item B<for_update BOOL>
If true, this parameter is translated to be the equivalent of passing the L<lock|/lock> parameter and setting the C<type> to C<for update>. For example, these are both equivalent:
$object->load(for_update => 1);
$object->load(lock => { type => 'for update' });
See the L<lock|/lock> parameter below for more information.
=item B<lock [ TYPE | HASHREF ]>
Load the object using some form of locking. These lock directives have database-specific behavior and not all directives are supported by all databases. The value should be a reference to a hash or a TYPE string, which is equivalent to setting the ...
$object->load(lock => 'for update');
$object->load(lock => { type => 'for update' });
Valid hash keys are:
=over 4
=item B<columns ARRAYREF>
lib/Rose/DB/Object.pm view on Meta::CPAN
B<SUBCLASS NOTE:> If you are going to override the L<load|/load> method in your subclass, you I<must> pass an I<alias to the actual object> as the first argument to the method, rather than passing a copy of the object reference. Example:
# This is the CORRECT way to override load() while still
# calling the base class version of the method.
sub load
{
my $self = $_[0]; # Copy, not shift
... # Do your stuff
shift->SUPER::load(@_); # Call superclass
}
Now here's the wrong way:
# This is the WRONG way to override load() while still
# calling the base class version of the method.
sub load
{
my $self = shift; # WRONG! The alias to the object is now lost!
... # Do your stuff
$self->SUPER::load(@_); # This won't work right!
}
This requirement exists in order to preserve some sneaky object-replacement optimizations in the base class implementation of L<load|/load>. At some point, those optimizations may change or go away. But if you follow these guidelines, your code wil...
=item B<not_found>
Returns true if the previous call to L<load|/load> failed because a row in the database table with the specified primary or unique key did not exist, false otherwise.
=item B<meta>
Returns the L<Rose::DB::Object::Metadata> object associated with this class. This object describes the database table whose rows are fronted by this class: the name of the table, its columns, unique keys, foreign keys, etc.
See the L<Rose::DB::Object::Metadata> documentation for more information.
=item B<save [PARAMS]>
Save the current object to the database table. In the absence of PARAMS, if the object was previously L<load|/load>ed from the database, the row will be L<update|/update>d. Otherwise, a new row will be L<insert|/insert>ed. PARAMS are name/value pa...
Actions associated with sub-objects that were added or deleted using one of the "*_on_save" relationship or foreign key method types are also performed when this method is called. If there are any such actions to perform, a new transaction is starte...
$product = Product->new(name => 'Sled');
$vendor = Vendor->new(name => 'Acme');
$product->vendor($vendor);
# Product and vendor records created and linked together,
# all within a single transaction.
$product->save;
See the "making methods" sections of the L<Rose::DB::Object::Metadata::Relationship|Rose::DB::Object::Metadata::Relationship/"MAKING METHODS"> and L<Rose::DB::Object::Metadata::ForeignKey|Rose::DB::Object::Metadata::ForeignKey/"MAKING METHODS"> docum...
Valid parameters to L<save()|/save> are:
=over 4
=item B<cascade BOOL>
If true, then sub-objects related to this object through a foreign key or relationship that have been previously loaded using methods called on this object and that contain unsaved changes will be L<saved|/save> after the parent object is saved. Thi...
All database operations are done within a single transaction. If the L<db|/db> is not currently in a transaction, a new transaction is started. If any part of the cascaded save fails, the transaction is rolled back.
If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_cascade_save|Rose::DB::Object::Metadata/default_cascade_save> class method, which returns false by default.
Example:
$p = Product->new(id => 123)->load;
print join(', ', $p->colors); # related Color objects loaded
$p->colors->[0]->code('zzz'); # one Color object is modified
# The Product object and the modified Color object are saved
$p->save(cascade => 1);
=item B<changes_only BOOL>
If true, then only the columns whose values have been modified will be included in the insert or update query. Otherwise, all eligible columns will be included. Note that any column that has a L<default|Rose::DB::Object::Metadata::Column/default> v...
If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_update_changes_only|Rose::DB::Object::Metadata/default_update_changes_only> class method on update, and the L<default_insert_changes_only|Rose::...
=item B<insert BOOL>
If set to a true value, then an L<insert|/insert> is attempted, regardless of whether or not the object was previously L<load|/load>ed from the database.
=item B<prepare_cached BOOL>
If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will save the object. If omitted, the default value is determined by the L<metadata ...
=item B<update BOOL>
If set to a true value, then an L<update|/update> is attempted, regardless of whether or not the object was previously L<load|/load>ed from the database.
=back
It is an error to pass both the C<insert> and C<update> parameters in a single call.
Returns true if the row was inserted or updated successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned i...
If an insert was performed and the primary key is a single column that supports auto-generated values, then the object accessor for the primary key column will contain the auto-generated value. See the L<Serial and Auto-Incremented Columns|/"Serial ...
=item B<update [PARAMS]>
Update the current object in the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be updated, rather than inserted. It is recommended that you use the L<save|/save> method i...
PARAMS are optional name/value pairs. Valid PARAMS are:
=over 4
=item B<changes_only BOOL>
If true, then only the columns whose values have been modified will be updated. Otherwise, all columns whose values have been loaded from the database will be updated. If omitted, the default value of this parameter is determined by the L<metadata ...
=item B<prepare_cached BOOL>
If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will insert the object. If omitted, the default value of this parameter is determine...
=back
Returns true if the row was updated successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of th...
=back
=head1 RESERVED METHODS
As described in the L<Rose::DB::Object::Metadata> documentation, each column in the database table has an associated get/set accessor method in the L<Rose::DB::Object>. Since the L<Rose::DB::Object> API already defines many methods (L<load|/load>, L...
Here is a list of method names reserved by the L<Rose::DB::Object> API. If you have a column with one of these names, you must alias it.
db
dbh
delete
DESTROY
error
( run in 1.069 second using v1.01-cache-2.11-cpan-39bf76dae61 )