Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 9b16f8f8

Von Moritz Bunkus vor mehr als 3 Jahren hinzugefügt

SL::DB::Object: Methode update_collections für One-To-Many-Relationships

Der große Nachteil einer direkten Zuweisung wie
z.B. `$customer->shiptos($::form->{shiptos} // [])` ist, dass Rose
erst mal alle Objekte der Relationship löscht (auch wenn die neuen
Werte Primärschlüsselattribute enthalten) und anschließend neu
INSERTed, was nicht nur deutlich zu aufwändig ist, sondern auch mal
nicht funktionieren kann, wenn es da noch weitere Objekte mit
Fremdschlüsseln auf die zu aktualisierenden Objekte verweisen.

Daher muss man die Behandlung (neu hinzuzufügende, zu löschende & zu
aktualisierende Objekte) selber vornehmen. Das macht nun diese
Methode.

Die Methode gleicht eine Liste von existierenden Objekten einer
One-To-Many-Relationship (z.B. Kunde zu Lieferadressen) mit einer
neuen Liste von Hashrefs ab, die z.B. aus `$::form` stammen können.

Für alle Einträge aus der neuen Liste, die kein Attribut für den
Primärschlüssel enthalten, werden neue Einträge in der Datenbank
angelegt.

Für alle Einträge aus der neuen Liste mit Primärschlüsselattribut wird
das korrespondierende Objekt mit den Werten aus `$::form`
aktualisiert.

Alle existierenden Objekte in `$self->$attribute`, für die es keinen
korrespondierenden Eintrag in der neuen Liste mehr gibt, werden
gelöscht.

Unterschiede anzeigen:

SL/DB/Object.pm
7 7
use Rose::DB::Object;
8 8
use Rose::DB::Object::Constants qw();
9 9
use List::MoreUtils qw(any pairwise);
10
use List::Util qw(first);
10 11

  
11 12
use SL::DB;
12 13
use SL::DB::Helper::Attr;
......
105 106
  return $self;
106 107
}
107 108

  
109
sub update_collection {
110
  my ($self, $attribute, $entries) = @_;
111

  
112
  my $self_primary_key = "" . ($self->meta->primary_key_columns)[0];
113

  
114
  croak "\$self hasn't been saved yet" if !$self->$self_primary_key;
115

  
116
  my $relationship = first { $_->name eq $attribute } @{ $self->meta->relationships };
117

  
118
  croak "No relationship found for attribute '$attribute'" if !$relationship;
119

  
120
  my @primary_key_columns = $relationship->class->meta->primary_key_columns;
121

  
122
  croak "Classes with multiple primary key columns are not supported" if scalar(@primary_key_columns) > 1;
123

  
124
  my $class             = $relationship->class;
125
  my $manager_class     = "SL::DB::Manager::" . substr($class, 8);
126
  my $other_primary_key = "" . $primary_key_columns[0];
127
  my $column_map        = $relationship->column_map;
128
  my @new_entries       = @{ $entries          // [] };
129
  my @existing_entries  = @{ $self->$attribute // [] };
130
  my @to_delete         = grep { my $value = $_->$other_primary_key; !any { $_->{$other_primary_key} == $value } @new_entries } @existing_entries;
131

  
132
  $_->delete for @to_delete;
133

  
134
  foreach my $entry (@new_entries) {
135
    if (!$entry->{$other_primary_key}) {
136
      my $new_instance = $class->new(%{ $entry });
137

  
138
      foreach my $self_attribute (keys %{ $column_map }) {
139
        my $other_attribute = $column_map->{$self_attribute};
140
        $new_instance->$other_attribute($self->$self_attribute);
141
      }
142

  
143
      $new_instance->save;
144

  
145
      next;
146
    }
147

  
148
    my $existing = first { $_->$other_primary_key == $entry->{$other_primary_key} } @existing_entries;
149
    $existing->update_attributes(%{ $entry }) if $existing;
150
  }
151
}
152

  
108 153
sub call_sub {
109 154
  my $self = shift;
110 155
  my $sub  = shift;
......
318 363
C<assign_attributes> function and saves the object afterwards. Returns
319 364
the object itself.
320 365

  
366
=item C<update_collection $attribute, $entries, %params>
367

  
368
Updates a one-to-many relationship named C<$attribute> to match the
369
entries in C<$entries>. C<$entries> is supposed to be an array ref of
370
hash refs.
371

  
372
For each hash ref in C<$entries> that does not contain a field for the
373
relationship's primary key column, this function creates a new entry
374
in the database with its attributes set to the data in the entry.
375

  
376
For each hash ref in C<$entries> that contains a field for the
377
relationship's primary key column, this function looks up the
378
corresponding entry in C<$self-&gt;$attribute> & updates its
379
attributes with the data in the entry.
380

  
381
All objects in C<$self-&gt;$attribute> for which no corresponding
382
entry exists in C<$entries> are deleted by calling the object's
383
C<delete> method.
384

  
385
In all cases the relationship itself C<$self-&gt;$attribute> is not
386
changed.
387

  
321 388
=item _get_manager_class
322 389

  
323 390
Returns the manager package for the object or class that it is called

Auch abrufbar als: Unified diff