X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=a6f5f7706a082ffefb26162b76174b88be969355;hb=daf4e3bed37d35feb43338142935dcb4c61313b8;hp=72bb2fcdc8edf9cfa8d504bb41e540ee2acfe413;hpb=497d874ac78f5b6bba1309001f62c299a9419499;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index 72bb2fc..a6f5f77 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -162,7 +162,7 @@ sub new { if ($attrs) { $new->throw_exception("attrs must be a hashref") unless ref($attrs) eq 'HASH'; - + my ($related,$inflated); ## Pretend all the rels are actual objects, unset below if not, for insert() to fix $new->{_rel_in_storage} = 1; @@ -235,7 +235,7 @@ sub new { } $new->throw_exception("No such column $key on $class") unless $class->has_column($key); - $new->store_column($key => $attrs->{$key}); + $new->store_column($key => $attrs->{$key}); } $new->{_relationship_data} = $related if $related; @@ -283,7 +283,7 @@ sub insert { my $rollback_guard; # Check if we stored uninserted relobjs here in new() - my %related_stuff = (%{$self->{_relationship_data} || {}}, + my %related_stuff = (%{$self->{_relationship_data} || {}}, %{$self->{_inflated_column} || {}}); if(!$self->{_rel_in_storage}) { @@ -332,7 +332,7 @@ sub insert { ## PK::Auto my @auto_pri = grep { - !defined $self->get_column($_) || + !defined $self->get_column($_) || ref($self->get_column($_)) eq 'SCALAR' } $self->primary_columns; @@ -377,7 +377,7 @@ sub insert { my $re = $self->result_source ->related_source($relname) ->resultset - ->find_or_create($them); + ->create($them); %{$obj} = %{$re}; MULTICREATE_DEBUG and warn "MC $self new $relname $obj"; } @@ -413,7 +413,7 @@ sub insert { Indicates whether the object exists as a row in the database or not. This is set to true when L, L or L -are used. +are used. Creating a row object using L, or calling L on one, sets it to false. @@ -519,14 +519,14 @@ values to locate the row. The object is still perfectly usable, but L will now return 0 and the object must be reinserted using L -before it can be used to L the row again. +before it can be used to L the row again. If you delete an object in a class with a C 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. Any database-level cascade or restrict will take precedence over a -DBIx-Class-based cascading delete. +DBIx-Class-based cascading delete. If you delete an object within a txn_do() (see L) and the transaction subsequently fails, the row object will remain marked as @@ -600,7 +600,7 @@ sub get_column { return $self->{_column_data}{$column} if exists $self->{_column_data}{$column}; if (exists $self->{_inflated_column}{$column}) { return $self->store_column($column, - $self->_deflated_column($column, $self->{_inflated_column}{$column})); + $self->_deflated_column($column, $self->{_inflated_column}{$column})); } $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column); return undef; @@ -702,7 +702,7 @@ sub get_dirty_columns { Throws an exception if the column does not exist. Marks a column as having been changed regardless of whether it has -really changed. +really changed. =cut sub make_column_dirty { @@ -711,7 +711,7 @@ sub make_column_dirty { $self->throw_exception( "No such column '${column}'" ) unless exists $self->{_column_data}{$column} || $self->has_column($column); - # the entire clean/dirty code relieas on exists, not on true/false + # the entire clean/dirty code relies on exists, not on true/false return 1 if exists $self->{_dirty_columns}{$column}; $self->{_dirty_columns}{$column} = 1; @@ -787,7 +787,10 @@ sub set_column { $self->store_column($column, $new_value); my $dirty; - if (defined $old_value xor defined $new_value) { + if (!$self->in_storage) { # no point tracking dirtyness on uninserted data + $dirty = 1; + } + elsif (defined $old_value xor defined $new_value) { $dirty = 1; } elsif (not defined $old_value) { # both undef @@ -799,8 +802,8 @@ sub set_column { else { # do a numeric comparison if datatype allows it my $colinfo = $self->column_info ($column); - # cache for speed - if (not defined $colinfo->{is_numeric}) { + # cache for speed (the object may *not* have a resultsource instance) + if (not defined $colinfo->{is_numeric} && $self->_source_handle) { $colinfo->{is_numeric} = $self->result_source->schema->storage->is_datatype_numeric ($colinfo->{data_type}) ? 1 @@ -829,7 +832,7 @@ sub set_column { $row->set_columns({ $col => $val, ... }); -=over +=over =item Arguments: \%columndata @@ -864,7 +867,7 @@ sub set_columns { =back Sets more than one column value at once. Any inflated values are -deflated and the raw values stored. +deflated and the raw values stored. Any related values passed as Row objects, using the relation name as a key, are reduced to the appropriate foreign key values and stored. If @@ -908,7 +911,7 @@ sub set_inflated_columns { } } } - $self->set_columns($upd); + $self->set_columns($upd); } =head2 copy @@ -954,7 +957,7 @@ sub copy { $new->set_inflated_columns($changes); $new->insert; - # Its possible we'll have 2 relations to the same Source. We need to make + # 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 esle we'll violate unique # constraints my $rels_copied = {}; @@ -963,7 +966,7 @@ sub copy { my $rel_info = $self->result_source->relationship_info($rel); next unless $rel_info->{attrs}{cascade_copy}; - + my $resolved = $self->result_source->_resolve_condition( $rel_info->{cond}, $rel, $new ); @@ -975,7 +978,7 @@ sub copy { $copied->{$id_str} = 1; my $rel_copy = $related->copy($resolved); } - + } return $new; } @@ -1050,7 +1053,6 @@ sub inflate_result { my $new = { _source_handle => $source_handle, _column_data => $me, - _in_storage => 1 }; bless $new, (ref $class || $class); @@ -1062,14 +1064,25 @@ sub inflate_result { unless $pre_source; if (ref($pre_val->[0]) eq 'ARRAY') { # multi my @pre_objects; - foreach my $pre_rec (@$pre_val) { - unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_} - and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) { - next; + + for my $me_pref (@$pre_val) { + + # the collapser currently *could* return bogus elements with all + # columns set to undef + my $has_def; + for (values %{$me_pref->[0]}) { + if (defined $_) { + $has_def++; + last; + } } - push(@pre_objects, $pre_source->result_class->inflate_result( - $pre_source, @{$pre_rec})); + next unless $has_def; + + push @pre_objects, $pre_source->result_class->inflate_result( + $pre_source, @$me_pref + ); } + $new->related_resultset($pre)->set_cache(\@pre_objects); } elsif (defined $pre_val->[0]) { my $fetched; @@ -1087,11 +1100,13 @@ sub inflate_result { } elsif ($accessor eq 'filter') { $new->{_inflated_column}{$pre} = $fetched; } else { - $class->throw_exception("Prefetch not supported with accessor '$accessor'"); + $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor '$accessor'"); } $new->related_resultset($pre)->set_cache([ $fetched ]); } } + + $new->in_storage (1); return $new; } @@ -1260,11 +1275,11 @@ sub get_from_storage { my $self = shift @_; my $attrs = shift @_; my $resultset = $self->result_source->resultset; - + if(defined $attrs) { $resultset = $resultset->search(undef, $attrs); } - + return $resultset->find($self->{_orig_ident} || $self->ident_condition); } @@ -1317,6 +1332,13 @@ This method can also be used to refresh from storage, retrieving any changes made since the row was last read from storage. Actually implemented in L +Note: If you are using L as your +storage, please kept in mind that if you L on a row that you +just updated or created, you should wrap the entire bit inside a transaction. +Otherwise you run the risk that you insert or update to the master database +but read from a replicant database that has not yet been updated from the +master. This will result in unexpected results. + =cut 1;