DBIx-Class
view release on metacpan or search on metacpan
lib/DBIx/Class/Row.pm view on Meta::CPAN
$result->update()->discard_changes();
To determine before calling this method, which column values have
changed and will be updated, call L</get_dirty_columns>.
To check if any columns will be updated, call L</is_changed>.
To force a column to be updated, call L</make_column_dirty> before
this method.
=cut
sub update {
my ($self, $upd) = @_;
$self->set_inflated_columns($upd) if $upd;
my %to_update = $self->get_dirty_columns
or return $self;
$self->throw_exception( "Not in database" ) unless $self->in_storage;
my $rows = $self->result_source->storage->update(
$self->result_source, \%to_update, $self->_storage_ident_condition
);
if ($rows == 0) {
$self->throw_exception( "Can't update ${self}: row not found" );
} elsif ($rows > 1) {
$self->throw_exception("Can't update ${self}: updated more than one row");
}
$self->{_dirty_columns} = {};
$self->{related_resultsets} = {};
delete $self->{_column_data_in_storage};
return $self;
}
=head2 delete
$result->delete
=over
=item Arguments: none
=item Return Value: L<$result|DBIx::Class::Manual::ResultClass>
=back
Throws an exception if the object is not in the database according to
L</in_storage>. Also throws an exception if a proper WHERE clause
uniquely identifying the database row can not be constructed (see
L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
for more details).
The object is still perfectly usable, but L</in_storage> will
now return 0 and the object must be reinserted using L</insert>
before it can be used to L</update> the row again.
If you delete an object in a class with a C<has_many> relationship, an
attempt is made to delete all the related objects as well. To turn
this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
hashref of the relationship, see L<DBIx::Class::Relationship>. Any
database-level cascade or restrict will take precedence over a
DBIx-Class-based cascading delete, since DBIx-Class B<deletes the
main row first> and only then attempts to delete any remaining related
rows.
If you delete an object within a txn_do() (see L<DBIx::Class::Storage/txn_do>)
and the transaction subsequently fails, the result object will remain marked as
not being in storage. If you know for a fact that the object is still in
storage (i.e. by inspecting the cause of the transaction's failure), you can
use C<< $obj->in_storage(1) >> to restore consistency between the object and
the database. This would allow a subsequent C<< $obj->delete >> to work
as expected.
See also L<DBIx::Class::ResultSet/delete>.
=cut
sub delete {
my $self = shift;
if (ref $self) {
$self->throw_exception( "Not in database" ) unless $self->in_storage;
$self->result_source->storage->delete(
$self->result_source, $self->_storage_ident_condition
);
delete $self->{_column_data_in_storage};
$self->in_storage(0);
}
else {
my $rsrc = try { $self->result_source_instance }
or $self->throw_exception("Can't do class delete without a ResultSource instance");
my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
$rsrc->resultset->search(@_)->delete;
}
return $self;
}
=head2 get_column
my $val = $result->get_column($col);
=over
=item Arguments: $columnname
=item Return Value: The value of the column
=back
Throws an exception if the column name given doesn't exist according
to L<has_column|DBIx::Class::ResultSource/has_column>.
Returns a raw column value from the result object, if it has already
been fetched from the database or set by an accessor.
If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
will be deflated and returned.
lib/DBIx/Class/Row.pm view on Meta::CPAN
need to preserve the hashref, it is sufficient to pass a shallow copy
to C<set_inflated_columns>, e.g. ( { %{ $href } } )
See also L<DBIx::Class::Relationship::Base/set_from_related>.
=cut
sub set_inflated_columns {
my ( $self, $upd ) = @_;
my $rsrc;
foreach my $key (keys %$upd) {
if (ref $upd->{$key}) {
$rsrc ||= $self->result_source;
my $info = $rsrc->relationship_info($key);
my $acc_type = $info->{attrs}{accessor} || '';
if ($acc_type eq 'single') {
my $rel_obj = delete $upd->{$key};
$self->set_from_related($key => $rel_obj);
$self->{_relationship_data}{$key} = $rel_obj;
}
elsif ($acc_type eq 'multi') {
$self->throw_exception(
"Recursive update is not supported over relationships of type '$acc_type' ($key)"
);
}
elsif (
$rsrc->has_column($key)
and
exists $rsrc->column_info($key)->{_inflate_info}
) {
$self->set_inflated_column($key, delete $upd->{$key});
}
}
}
$self->set_columns($upd);
}
=head2 copy
my $copy = $orig->copy({ change => $to, ... });
=over
=item Arguments: \%replacementdata
=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> copy
=back
Inserts a new row into the database, as a copy of the original
object. If a hashref of replacement data is supplied, these will take
precedence over data in the original. Also any columns which have
the L<column info attribute|DBIx::Class::ResultSource/add_columns>
C<< is_auto_increment => 1 >> are explicitly removed before the copy,
so that the database can insert its own autoincremented values into
the new object.
Relationships will be followed by the copy procedure B<only> if the
relationship specifies a true value for its
L<cascade_copy|DBIx::Class::Relationship::Base> attribute. C<cascade_copy>
is set by default on C<has_many> relationships and unset on all others.
=cut
sub copy {
my ($self, $changes) = @_;
$changes ||= {};
my $col_data = { $self->get_columns };
my $rsrc = $self->result_source;
my $colinfo = $rsrc->columns_info;
foreach my $col (keys %$col_data) {
delete $col_data->{$col}
if ( ! $colinfo->{$col} or $colinfo->{$col}{is_auto_increment} );
}
my $new = { _column_data => $col_data };
bless $new, ref $self;
$new->result_source($rsrc);
$new->set_inflated_columns($changes);
$new->insert;
# Its possible we'll have 2 relations to the same Source. We need to make
# sure we don't try to insert the same row twice else we'll violate unique
# constraints
my $rel_names_copied = {};
foreach my $rel_name ($rsrc->relationships) {
my $rel_info = $rsrc->relationship_info($rel_name);
next unless $rel_info->{attrs}{cascade_copy};
my $resolved = $rsrc->_resolve_condition(
$rel_info->{cond}, $rel_name, $new, $rel_name
);
my $copied = $rel_names_copied->{ $rel_info->{source} } ||= {};
foreach my $related ($self->search_related($rel_name)->all) {
$related->copy($resolved)
unless $copied->{$related->ID}++;
}
}
return $new;
}
=head2 store_column
$result->store_column($col => $val);
=over
=item Arguments: $columnname, $value
=item Return Value: The value sent to storage
=back
Set a raw value for a column without marking it as changed. This
method is used internally by L</set_column> which you should probably
be using.
This is the lowest level at which data is set on a result object,
extend this method to catch all data setting methods.
=cut
sub store_column {
my ($self, $column, $value) = @_;
$self->throw_exception( "No such column '${column}' on " . ref $self )
unless exists $self->{_column_data}{$column} || $self->result_source->has_column($column);
$self->throw_exception( "set_column called for ${column} without value" )
if @_ < 3;
return $self->{_column_data}{$column} = $value;
}
=head2 inflate_result
Class->inflate_result($result_source, \%me, \%prefetch?)
=over
=item Arguments: L<$result_source|DBIx::Class::ResultSource>, \%columndata, \%prefetcheddata
=item Return Value: L<$result|DBIx::Class::Manual::ResultClass>
=back
All L<DBIx::Class::ResultSet> methods that retrieve data from the
database and turn it into result objects call this method.
( run in 0.873 second using v1.01-cache-2.11-cpan-d8267643d1d )