Home  >  Article  >  Backend Development  >  Data mapper of data source architecture pattern

Data mapper of data source architecture pattern

巴扎黑
巴扎黑Original
2016-11-12 10:43:431021browse

The table data entry of the data source architecture mode, the row of data source architecture mode, and the activity record of the data entry data source architecture mode were introduced earlier. Compared with these three data source architecture modes, the data mapper appears to be more "high-end" ".

1. Concept

Data Mapper: A mapper layer that moves data between objects and databases (and the mapper itself) while keeping them independent of each other. Concepts are always abstract. Simply put, a data mapper is a class data responsible for mapping data to objects.

2. Why use data mapper?

The data mapper is more complex to implement than the first three modes, so why use it?

The organizational relationship between objects is different from the tables in a relational database. A database table can be viewed as a grid composed of rows and columns. A row in the table can be related to a row in another table (even the same table) through a foreign key, and the organizational relationship of objects is more complex: an object may contain Other objects; different data structures may organize the same objects in different ways.

This divergence between object and relational databases is called "object-relational impedance mismatch" or "impedance mismatch".

The data mapper can solve this problem very well. It is responsible for the conversion of data between object and relational databases, thereby effectively hiding database operations in the domain model and managing inevitable conflicts in database conversion.

3. Simple implementation of data mapper

Php code

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);  
?>

The code omits some auxiliary classes and retains the main domain objects and data mapper. The most powerful thing about the Data Mapper pattern is that it removes the coupling between the domain layer and database operations. Mapper objects work behind the scenes and can be applied to various object-relational mappings. What this brings is the need to create a large number of specific mapper classes. But now the framework can be automatically generated through the program.

4. Timing of use

The main reason to use the database mapper is when the database scheme and the object model need to evolve independently of each other. The most common is of course used with domain patterns. Whether in the design phase, development phase, or testing phase, the data mapper does not need to consider the database when operating on the domain model. Domain objects know nothing about the structure of the database because all these correspondences are done by the data mapper.

Of course, data mappers introduce a new layer, so the prerequisite for using these patterns is the complexity of the business logic, which is not necessary if it is simple.

I would not use a data mapper without a domain model. But can you use the domain model without a data mapper? If the domain model is simple and the database is under the control of the domain model developer, it is reasonable for domain objects to access the database directly using activity records.

No need to create a complete database mapping layer. Creating such a data mapper is complex. In most cases, it is recommended to use an open source database mapping layer instead of creating it yourself


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn