Heim >Backend-Entwicklung >PHP-Tutorial >Datenzuordnung des Datenquellenarchitekturmusters
Die Tabellendateneingabe des Datenquellenarchitekturmodus, die Zeile des Datenquellenarchitekturmodus und der Aktivitätsdatensatz des Datenquellenarchitekturmodus wurden im Vergleich zu diesen drei Datenquellenarchitekturmodi früher eingeführt Mapper ist eher „groß und luxuriös“.
1. Konzept
Daten-Mapper: Eine Zuordnung, die Daten zwischen Objekten und Datenbanken (und dem Mapper selbst) verschiebt und sie dabei unabhängig voneinander auf Geräteebene hält. Konzepte sind immer abstrakt. Einfach ausgedrückt ist ein Daten-Mapper eine Datenklasse, die für die Zuordnung von Daten zu Objekten verantwortlich ist.
2. Warum Data Mapper verwenden?
Der Data Mapper ist komplexer zu implementieren als die ersten drei Modi, warum also ihn verwenden?
Die organisatorischen Beziehungen zwischen Objekten unterscheiden sich von Tabellen in relationalen Datenbanken. Eine Datenbanktabelle kann als ein aus Zeilen und Spalten bestehendes Raster betrachtet werden. Eine Zeile in der Tabelle kann über einen Fremdschlüssel mit einer Zeile in einer anderen Tabelle (sogar derselben Tabelle) verknüpft werden, und die organisatorische Beziehung von Objekten ist komplexer: Ein Objekt kann andere Objekte enthalten. Verschiedene Datenstrukturen können dieselben Objekte auf unterschiedliche Weise organisieren.
Diese Divergenz zwischen Objekt- und relationalen Datenbanken wird als „objektrelationale Impedanzfehlanpassung“ oder „Impedanzfehlanpassung“ bezeichnet.
Der Data Mapper kann dieses Problem sehr gut lösen. Er ist für die Konvertierung von Daten zwischen Objekt- und relationalen Datenbanken verantwortlich, wodurch Datenbankoperationen effektiv im Domänenmodell ausgeblendet werden und die unvermeidlichen Änderungen bei der Datenbankkonvertierung verwaltet werden.
3. Einfache Implementierung des Daten-Mappers
PHP-Code
<?php //领域抽象类 abstract class DomainObject { private $id = -1; function __construct( $id=null ) { if ( is_null( $id ) ) { $this->markNew(); } else { $this->id = $id; } } function getId( ) { return $this->id; } static function getCollection( $type ) { //这里通过一个工广生成此对象对应的数组数据对象 return HelperFactory::getCollection( $type ); } function collection() { return self::getCollection( get_class( $this ) ); } function finder() { return self::getFinder( get_class( $this ) ); } static function getFinder( $type ) { //这里通过一个工厂生成此对象对应的map对象 return HelperFactory::getFinder( $type ); } function setId( $id ) { $this->id = $id; } function __clone() { $this->id = -1; } } //场所类 class Venue extends DomainObject { private $name; private $spaces; function __construct( $id=null, $name=null ) { $this->name = $name; parent::__construct( $id ); } function setSpaces( SpaceCollection $spaces ) { $this->spaces = $spaces; } function getSpaces() { if ( ! isset( $this->spaces ) ) { //创建对应的SpaceMapper对象 $finder = self::getFinder( 'Space' ); $this->spaces = $finder->findByVenue( $this->getId() ); //$this->spaces = self::getCollection("Space"); } return $this->spaces; } function addSpace( Space $space ) { $this->getSpaces()->add( $space ); $space->setVenue( $this ); } function setName( $name_s ) { $this->name = $name_s; } function getName( ) { return $this->name; } static function findAll() { $finder = self::getFinder( __CLASS__ ); return $finder->findAll(); } static function find( $id ) { $finder = self::getFinder( __CLASS__ ); return $finder->find( $id ); } } abstract class Mapper{ protected static $PDO; function __construct() { if ( ! isset(self::$PDO) ) { //此处可加缓存 self::$PDO = new PDO( $dsn ); self::$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } } private function getFromMap( $id ) { //从内存取出此$id的DomainObject对象 } private function addToMap( DomainObject $obj ) { //将此DomainObject对象加入到内存 } function find( $id ) { $old = $this->getFromMap( $id ); if ( $old ) { return $old; } $this->selectstmt()->execute( array( $id ) ); $array = $this->selectstmt()->fetch( ); $this->selectstmt()->closeCursor( ); if ( ! is_array( $array ) ) { return null; } if ( ! isset( $array['id'] ) ) { return null; } $object = $this->createObject( $array ); return $object; } function findAll( ) { $this->selectAllStmt()->execute( array() ); return $this->getCollection( $this->selectAllStmt()->fetchAll( PDO::FETCH_ASSOC ) ); } function createObject( $array ) { $old = $this->getFromMap( $array['id']); if ( $old ) { return $old; } $obj = $this->doCreateObject( $array ); $this->addToMap( $obj ); return $obj; } function insert( DomainObject $obj ) { $this->doInsert( $obj ); $this->addToMap( $obj ); } protected abstract function getCollection( array $raw ); protected abstract function doCreateObject( array $array ); protected abstract function doInsert( DomainObject $object ); protected abstract function targetClass(); protected abstract function selectStmt( ); protected abstract function selectAllStmt( ); } class VenueMapper extends Mapper { function __construct() { parent::__construct(); $this->selectAllStmt = self::$PDO->prepare( "SELECT * FROM venue"); $this->selectStmt = self::$PDO->prepare( "SELECT * FROM venue WHERE id=?"); $this->updateStmt = self::$PDO->prepare( "UPDATE venue SET name=?, id=? WHERE id=?"); $this->insertStmt = self::$PDO->prepare( "INSERT into venue ( name ) values( ? )"); } function getCollection( array $raw ) { //这里简单起见用个对象数组 $ret = array(); foreach ($raw as $value) { $ret[] = $this->createObject($value); } return $ret; } protected function doCreateObject( array $array ) { $obj = new Venue( $array['id'] ); $obj->setname( $array['name'] ); //$space_mapper = new SpaceMapper(); //$space_collection = $space_mapper->findByVenue( $array['id'] ); //$obj->setSpaces( $space_collection ); return $obj; } protected function targetClass() { return "Venue"; } protected function doInsert( DomainObject $object ) { $values = array( $object->getname() ); $this->insertStmt->execute( $values ); $id = self::$PDO->lastInsertId(); $object->setId( $id ); } function update( DomainObject $object ) { $values = array( $object->getname(), $object->getid(), $object->getId() ); $this->updateStmt->execute( $values ); } function selectStmt() { return $this->selectStmt; } function selectAllStmt() { return $this->selectAllStmt; } } //client代码 $venue = new venue(); $venue->setName("XXXXXXX"); //插入一条数据 $mapper = new VenueMapper(); $mapper->insert($venue); //获取刚插入的数据 $venueInfo = $mapper->find($venue->getId()); //修改数据 $venue->setName('OOOOOOOOOOO'); $mapper->update($venue); ?>
Der Code lässt einige Hilfsklassen weg und behält die Hauptdomänenobjekte und den Daten-Mapper bei. Das Leistungsstärkste am Data Mapper-Muster ist, dass es die Kopplung zwischen der Domänenschicht und Datenbankoperationen aufhebt. Mapper-Objekte arbeiten im Hintergrund und können auf verschiedene objektrelationale Zuordnungen angewendet werden. Dies bringt die Notwendigkeit mit sich, eine große Anzahl spezifischer Mapper-Klassen zu erstellen. Aber jetzt kann das Framework automatisch durch das Programm generiert werden.
4. Zeitpunkt der Verwendung
Der Datenbank-Mapper wird hauptsächlich verwendet, wenn das Datenbankschema und das Objektmodell unabhängig voneinander weiterentwickelt werden müssen. Am gebräuchlichsten ist natürlich die Verwendung bei Domänenmustern. Ob in der Entwurfsphase, Entwicklungsphase oder Testphase, der Data Mapper muss die Datenbank nicht berücksichtigen, wenn er mit dem Domänenmodell arbeitet. Domänenobjekte wissen nichts über die Struktur der Datenbank, da alle diese Korrespondenzen vom Data Mapper durchgeführt werden.
Natürlich führt der Data Mapper eine neue Ebene ein, daher ist die Voraussetzung für die Verwendung dieser Muster die Komplexität der Geschäftslogik, die nicht erforderlich ist, wenn sie einfach ist.
Ich würde keinen Data Mapper ohne Domänenmodell verwenden. Aber können Sie das Domänenmodell ohne Data Mapper verwenden? Wenn das Domänenmodell einfach ist und die Datenbank unter der Kontrolle des Domänenmodellentwicklers steht, ist es sinnvoll, dass Domänenobjekte mithilfe von Aktivitätsdatensätzen direkt auf die Datenbank zugreifen.
Es ist nicht erforderlich, eine vollständige Datenbankzuordnungsebene zu erstellen. Die Erstellung eines solchen Datenmappers ist komplex. In den meisten Fällen wird empfohlen, eine Open-Source-Datenbankzuordnungsschicht zu verwenden, anstatt sie selbst zu erstellen