8 Stimmen

Wie sieht ein Data Mapper typischerweise aus?

Ich habe eine Tabelle namens Cat und eine PHP-Klasse namens Cat. Jetzt möchte ich eine CatDataMapper-Klasse erstellen, damit Cat CatDataMapper erweitert.

Ich möchte, dass diese Data Mapper-Klasse grundlegende Funktionen zur Durchführung von ORM und zum Erstellen, Bearbeiten und Löschen von Katzen bereitstellt.

Zu diesem Zweck könnte jemand, der dieses Muster sehr gut kennt, mir einige nützliche Ratschläge geben? Ich finde es etwas zu einfach, einfach einige Funktionen wie update(), delete(), save() bereitzustellen.

Ich erkenne ein Problem bei einem Data Mapper: Zuerst erstellt man die Instanz von Cat, dann initialisiert man alle Variablen wie Name, Fellfarbe, Augenfarbe, Schnurren, Miauen, Pfleger usw. und nachdem alles eingerichtet ist, ruft man die save()-Funktion auf, die von CatDataMapper geerbt wurde. Das war einfach ;) Aber nun das eigentliche Problem: Wenn man die Datenbank nach Katzen abfragt, erhält man einen einfachen, langweiligen Datensatz mit vielen Katzen-Daten zurück.

PDO bietet einige ORM-Fähigkeiten, um Cat-Instanzen zu erstellen. Nehmen wir an, ich benutze das, oder nehmen wir sogar an, ich habe eine mapDataset()-Funktion, die ein assoziatives Array akzeptiert. Sobald ich jedoch mein Cat-Objekt aus einem Datensatz habe, habe ich redundante Daten. Gleichzeitig könnten zwanzig Benutzer dieselben Katzen-Daten aus der Datenbank abrufen und das Katzenobjekt bearbeiten, d.h. die Katze umbenennen und speichern(), während ein anderer Benutzer noch darüber nachdenkt, eine andere Fellfarbe festzulegen. Wenn alle ihre Bearbeitungen speichern, ist alles durcheinander.

Äh... ok, um diese Frage wirklich kurz zu halten: Was ist hier die bewährte Praxis?

12voto

Gordon Punkte 304254

Von DataMapper in PoEA

Der Data Mapper ist eine Softwareschicht, die die Objekte im Speicher von der Datenbank trennt. Seine Verantwortung besteht darin, Daten zwischen den beiden zu übertragen und sie auch voneinander zu isolieren. Mit Data Mapper müssen die Objekte im Speicher nicht einmal wissen, dass eine Datenbank vorhanden ist; sie benötigen keinen SQL-Interface-Code und sicherlich kein Wissen über das Datenbankschema. (Das Datenbankschema ist immer unwissend über die Objekte, die es verwenden.) Da es sich um eine Form des Mappers (473) handelt, ist Data Mapper selbst der Domänenschicht unbekannt.

Ein Cat sollte daher nicht CatDataMapper erweitern, da dies eine ist-eine Beziehung schaffen und die Katze mit der Persistenzschicht verknüpfen würde. Wenn Sie die Persistenz Ihrer Katzen auf diese Weise behandeln möchten, sollten Sie sich ActiveRecord oder eine der anderen Datenquellenarchitekturmuster ansehen.

Normalerweise verwenden Sie einen DataMapper, wenn Sie ein Domänenmodell verwenden. Ein einfacher DataMapper würde einfach eine Datenbanktabelle auf der Basis eines Feldes auf eine entsprechende In-Memory-Klasse abbilden. Wenn jedoch der Bedarf an einem DataMapper entsteht, haben Sie normalerweise nicht solche einfachen Beziehungen. Tabellen werden nicht im Verhältnis 1:1 zu Ihren Objekten abgebildet. Stattdessen können mehrere Tabellen zu einem Objektverbund und umgekehrt zusammengefasst werden. Folglich kann die Implementierung nur von CRUD-Methoden schnell zu einer echten Herausforderung werden.

Abgesehen davon ist es eines der komplizierteren Muster (umfasst 15 Seiten in PoEA), das häufig in Kombination mit dem Repository-Muster und anderen verwendet wird. Schauen Sie sich in der rechten Spalte dieser Seite die verwandten Fragen an für ähnliche Fragen.

Was Ihre Frage zu mehreren Benutzern betrifft, die dieselbe Katze bearbeiten, handelt es sich um ein häufiges Problem, das als Concurrency bezeichnet wird. Eine Lösung hierfür wäre, die Zeile zu sperren, während jemand sie bearbeitet. Aber wie bei allem kann dies zu anderen Problemen führen.

2voto

Konel Sum Punkte 591

Wenn Sie auf ORM's wie Doctrine oder Propel vertrauen, lautet das Grundprinzip, eine statische Klasse zu erstellen, die die tatsächlichen Daten aus der Datenbank abruft (Propel würde beispielsweise CatPeer erstellen), und die von der Peer-Klasse abgerufenen Ergebnisse würden dann in Cat-Objekte "hydratisiert".

Der Hydratisierungsprozess ist der Prozess der Umwandlung eines "einfachen langweiligen" MySQL-Ergebnissets in schöne Objekte mit Gettern und Settern.

Also für eine Abfrage würde man etwas wie CatPeer::doSelect() verwenden. Dann für ein neues Objekt würden Sie es zuerst instanziieren (oder eine Instanz aus der Datenbank abrufen): $cat = new Cat();

Die Einfügung wäre so einfach wie: $cat->save(); Das wäre gleichbedeutend mit einem Einfügen (oder einem Aktualisieren, wenn das Objekt bereits in der Datenbank vorhanden ist... Das ORM sollte wissen, wie der Unterschied zwischen neuen und vorhandenen Objekten gemacht wird, indem beispielsweise die Anwesenheit oder Abwesenheit eines Primärschlüssels verwendet wird).

2voto

K. Norbert Punkte 10316

Die Implementierung eines Data Mappers ist sehr schwierig in PHP < 5.3, da Sie nicht auf geschützte/private Felder zugreifen/schreiben können. Sie haben ein paar Möglichkeiten beim Laden und Speichern der Objekte:

  1. Verwenden Sie eine Art Workaround, z. B. indem Sie das Objekt serialisieren, die Zeichenfolgendarstellung ändern und sie dann mit unserialize zurückbringen
  2. Machen Sie alle Felder öffentlich
  3. Halten Sie sie privat/geschützt und schreiben Sie Zugriffsmethoden für jedes von ihnen

Die erste Methode birgt die Möglichkeit, bei einer neuen Veröffentlichung zu versagen, und ist ein sehr grobes Hack, die zweite Methode gilt als (sehr) schlechte Praxis.

Auch die dritte Option wird als schlechte Praxis angesehen, da Sie nicht für alle Felder getter/setter bereitstellen sollten, sondern nur für diejenigen, die es benötigen. Ihr Modell wird aus rein DDD (domain driven design) Sicht "beschädigt", da es Methoden enthält, die nur aufgrund des Persistenzmechanismus benötigt werden. Es bedeutet auch, dass Sie jetzt eine weitere Zuordnung für die Felder -> Setter-Methoden beschreiben müssen, neben den Feldern -> Tabellenspalten.

PHP 5.3 führt die Möglichkeit ein, auf alle Arten von Feldern zuzugreifen/ändern, indem Sie Reflektion verwenden:

http://hu2.php.net/manual/en/reflectionproperty.setaccessible.php

Mit diesem Feature können Sie einen echten Data Mapper realisieren, da die Notwendigkeit entfällt, Setter für alle Felder bereitzustellen.

1voto

prodigitalson Punkte 59250

PDO bietet einige ORM-Funktionen, um Cat-Instanzen zu erstellen. Angenommen, ich benutze das, oder nehmen wir sogar an, ich habe eine mapDataset()-Funktion, die ein assoziatives Array annimmt. Sobald ich jedoch mein Cat-Objekt aus einem Datensatz habe, habe ich redundante Daten. Gleichzeitig könnten zwanzig Benutzer dieselben Katzen-Daten aus der Datenbank abrufen und das Katzenobjekt bearbeiten, d.h. die Katze umbenennen und sie speichern(), während ein anderer Benutzer noch darüber nachdenkt, eine andere Fellfarbe einzustellen. Wenn sie alle ihre Änderungen speichern, ist alles durcheinander.

Um den Status der Daten typischerweise nachzuverfolgen, würden IdentityMap und/oder UnitOfWork verwendet werden, um alle verschiedenen Operationen an zugeordneten Entitäten zu verfolgen... und am Ende des Anfragezyklus würden dann alle Operationen durchgeführt.

0voto

erenon Punkte 18471

Halte die Antwort kurz: Du hast eine Instanz von Cat. (Vielleicht erweitert sie CatDbMapper oder Cat3rdpartycatstoreMapper) Du rufst auf:

$cats = $cat_model->getBlueEyedCats();
//dann bekommst du ein Array von Cat-Objekten im $cats-Array

Wenn du nicht weißt, was du benutzt, könntest du dir ein PHP-Framework ansehen, um es besser zu verstehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X