Speichern der Entität als weitere Zeile in Lehre 2

77

Nehmen wir an, ich habe eine Entität $e. Gibt es eine generische Möglichkeit, es als eine andere Zeile zu speichern, die dieselben Entitätsdaten, aber einen anderen Primärschlüssel enthält?

Warum ich das brauche: Ich implementiere eine Art temporäres Datenbankschema und anstatt die Zeile zu aktualisieren, muss ich nur ein neues erstellen.

zerkms
quelle
Haben Sie es versucht, ganz oben auf meinem Kopf (dh ungetestet) $f = clone $e? Möglicherweise müssen Sie die __clone()Methode implementieren
Phil
4
@Phil: Die geklonte Entität hat dieselbe PK und aktualisiert daher nur dieselbe Zeile. Und noch überraschender - spl_object_hash(Doctrine verwendet es, um bestimmte Instanzen zu identifizieren) sind für das Original und das geklonte Objekt gleich, obwohl sie unterschiedliche Daten enthalten
zerkms
@Phil: __clone()würde auch nicht helfen - Doctrine verwendet $oid = spl_object_hash($entity);und eine interne Karte, um den Status des Objekts zu erhalten. Und für beide (das Original und das geklonte) wäre es das gleiche -MANAGED
zerkms
1
das ist nicht wahr. Der Klon $ e gibt eine andere Instanz und damit einen weiteren Wert für spl_object_hash () zurück.
Florian Klein
1
Versuchte und war sich dessen sowieso sicher. Ein Klon ist eine andere Instanz. Bis Sie die UnitOfWork / identityMap auffordern, ihn zu registrieren, wird diese Entität als INSERTed betrachtet.
Florian Klein

Antworten:

161

Versuchen Sie das Klonen und fügen Sie Ihrer Entität die folgende Methode hinzu

public function __clone() {
    $this->id = null;
}

Sie müssen möglicherweise trennen das Unternehmen , bevor es persistierenden. Ich habe meine Entwicklungsmaschine momentan nicht zur Hand, um dies zu testen.

$f = clone $e;
$em->detach($f);
$em->persist($f);
$em->flush();

Aktualisieren

Ich habe gerade versucht, eine einfache SQLite-Demo zu verwenden. Sie sollten nichts tun müssen. Das Folgende funktionierte für mich, ohne eine __clone()Methode hinzuzufügen oder etwas Ungewöhnliches zu tun

$new = clone $old;
$em->persist($new);
$em->flush();

Nach dem Löschen hatte die $newEntität eine neue ID und wurde als neue Zeile in der Datenbank gespeichert.

Ich würde die ID-Eigenschaft immer noch über die __clone()Methode auf Null setzen , da dies aus einer reinen Modellansicht sinnvoll ist.

Update 2

Dies liegt daran, dass die generierten Proxy-Klassen __clone()mit dieser wichtigen Zeile implementiert werden

unset($this->_entityPersister, $this->_identifier);
Phil
quelle
6
Als ich diese Methode ausprobierte, wurden alle Änderungen an der ursprünglichen Entität auch in der Datenbank beibehalten und ein neuer Datensatz eingefügt. Dies liegt daran, dass der Entitätsmanager es weiterhin verwaltet. Selbst wenn ich die ursprüngliche Entität trenne, bleiben die Änderungen erhalten. Ich weiß nicht warum oder wie ich den Entitätsmanager erfolgreich dazu bringen kann, die Verwaltung der ursprünglichen Entität zu beenden (dh die Änderungen zu verwerfen). Weder noch $em->refresh($old)oder $em->detach($old)scheinen zu funktionieren ...
Chadwick Meyer
2
Wenn Sie implementieren __clone()möchten, stellen Sie sicher, dass Sie dies sicher tun, wie in der Dokumentation gezeigt. Andernfalls können Sie leicht Probleme verursachen.
Yep_It's_Me
2
Bitte beachten Sie, dass die Implementierung der __clone () -Methode nur funktioniert, wenn flache Objekte ohne Beziehungen vorhanden sind. Insbesondere werden nur Daten kopiert, die nicht auf andere Objekte verweisen. Alle Verweise sind dieselben wie im Originalobjekt.
Barbieswimcrew
2
@ Barbieswimcrew richtig. Ich habe eine andere Antwort, die sich mit diesem Szenario befasst
Phil
2
@ Yep_It's_Me hier ist ein ununterbrochener (atm) Link zur Doktrin-Dokumentation, wie man Klone implementiert oder aufwacht
Dimitry K
-3

Hier ist eine einfache Strategie, die ich verwendet habe und die keine übermäßige Komplexität beinhaltet:

$new->fromArray( $old->toArray() );
$new->id = NULL;
duftend
quelle
2
Woher kommen fromArrayund toArrayMethoden?
Zerkms
Verwenden Sie keine Doctrine_CollectionObjekte?
duftend
1
Ich verwende nur einfache PHP-Objekte, die nur die Daten enthalten und Accessor / Mutator-Methoden bereitstellen, um darauf zuzugreifen / sie zu ändern. Es erweitert keine Doctrine-Klassen
zerkms