简体   繁体   English

生成DAO类的最佳最快方法

[英]Best and Faster way for generate DAO class

I have reed a lot of pages about how generate a DAO class using PDO but I haven't find a good and faster way for obtain it. 我已经阅读了很多有关如何使用PDO生成DAO类的页面,但是我还没有找到一种更好且更快的方法来获取它。

Suppose we have a Database table called Animals with this structure 假设我们有一个名为Animals的数据库表,其结构如下

CREATE TABLE animals
(
    idAnimal int PRIMARY KEY NOT NULL AUTO_INCREMENT,
    name varchar(20),
    dateOfBirth DATETIME
);

A good way of development is create two class: Animals and AnimalsDAO like this 一个好的发展方式是创建两个类: AnimalsAnimalsDAO像这样

class Animals{
    /**
     * @var integer
     */
    public $idAnimal;
    /**
     * @var string
     */
    public $name;
    /**
     * @var DateTime
     */
    public $dateOfBirth;

    /**
     * Animals constructor.
     * @param int $idAnimal
     * @param string $name
     * @param DateTime $dateOfBirth
     */
    public function __construct($idAnimal, $name, DateTime $dateOfBirth) {
        $this->idAnimal = $idAnimal;
        $this->name = $name;
        $this->dateOfBirth = $dateOfBirth;
    }

}

In the AnimalsDAO generally there is the method for insert and retrive the object from database. AnimalsDAO通常存在一种用于从数据库中插入和检索对象的方法。 And in this class there is already an ORM problems (ORM Object Relation Mapping) because the fetch method of PDO don't work properly with object casting For years I have develop DAO in this way 在此类中,已经存在一个ORM问题(ORM对象关系映射),因为PDO的获取方法不能与对象强制转换一起正常工作。多年来,我一直以这种方式开发DAO

class ClienteDAO {
    /**
     * @param $idAnimal integer
     * @return Cliente
     * @throws Exception
     */
    public static function getClienteById($idAnimal ){

        $q="SELECT * FROM animals WHERE idAnimal =:idanim";
        $sth=PDOConnection::instance()->prepare($q);
        $sth->bindParam(':idanim', $idCliente,PDO::PARAM_INT);
        if($sth->execute()==0)
            throw new PDOException("ERROR EXECUTE");
        if($sth->rowCount()!=1)
            throw new PDOException("ERROR ROW NUMBERS");
        $row=$sth->fetch(PDO::FETCH_NUM);
        $row[2]=new DateTime($row[2]);
        return new Animals(...$row);
    }
}

So then if I change add or remove a database field, I have to only edit the variable in the Animal class, regenerate the constructor (I use PhpStorm) and edit eventually the rows after the fetch 因此,如果我更改添加或删除数据库字段,则只需编辑Animal类中的变量,重新生成构造函数(我使用PhpStorm),并在获取后最终编辑行

Exist a best and faster way for generate the DAO class ? 是否存在生成DAO类的最佳且更快的方法? (Another way is retrive the class attribute name and use the fetch Names method but there is again the casting problems with dateTime columns) (另一种方法是检索类属性名称并使用fetch Names方法,但dateTime列仍然存在转换问题)

The problems is more complicate when there is an inheritance into DataBase solved with association and the inheritance is in the php class 当通过关联解决了对数据库的继承问题并且该继承问题在php类中时,问题更加复杂

ER DIAGRAM ER图

And the database structure is translated in DATABASE STRUCTURE 数据库结构被翻译成数据库结构

Obviously, on the php side there is a father super class and two child class (extends the fater class) 显然,在php端有一个父超级类和两个子类(扩展了更胖的类)

How is the faster way for generate the DAO method for the child ? 如何为孩子生成DAO方法的更快方法?

As per OP req, an example from my Codebase 根据OP req,来自我的代码库的一个示例

Device 设备

namespace DAO;

use common\Context;
use enums\DeviceOStypeEnum;
use NAO\Inbound\IBDeviceSpec;
use NAO\Outbound\OBDevice;
use protocols\IClassInit;
use protocols\ITokenizer;
use traits\ClassInitTrait;

class Device extends AbstractDataObject implements IClassInit , ITokenizer
{

    const APPLE_PERMANENT_DEVICE_GUID    = "f8d55ac7-6e6a-4a0c-a5ec-20df1f384d62";
    const GOOGLE_PERMANENT_DEVICE_GUID   = "788996ff-5da3-47f2-9601-3f9ae79b51aa";

    use ClassInitTrait;

    /** @var  int $id */
    protected $id;
    /** @var  string $deviceGuid */
    var $deviceGuid;
    /** @var  DeviceOStypeEnum $osType */
    var $osType;
    /** @var  Version $osVersion */
    var $osVersion;
    /** @var  string $manufacturer */
    var $manufacturer;
    /** @var  string $modelCode */
    var $modelCode;
    /** @var  \DateTime $createdOn */
    var $createdOn;
    /**@var \DateTime $lastSeen */
    var $lastSeen;
    /** @var  bool $active */
    var $active;
    /** @var $isPhone */
    var $isPhone;
    /** @var  App $app */
    var $app;

    public static function postInit($c , $isTraceEnabled , $isPDOuser)
    {
    }

    /**
     * Device constructor.
     *
     * @param int $id
     * @param string $deviceGuid
     * @param DeviceOStypeEnum $osType
     * @param Version $osVersion
     * @param string $manufacturer
     * @param string $modelCode
     * @param \DateTime $createdOn
     * @param \DateTime $lastSeen
     * @param App $app
     * @param bool $isPhone
     * @param bool $active
     */
    public function __construct($id , $deviceGuid ,
                                $osType , $osVersion , $manufacturer , $modelCode ,
                                \DateTime $createdOn , \DateTime $lastSeen ,
                                $active , $isPhone , $app)
    {
        $this->id           = $id;
        $this->deviceGuid   = $deviceGuid;
        $this->osType       = $osType;
        $this->osVersion    = $osVersion;
        $this->manufacturer = $manufacturer;
        $this->modelCode    = $modelCode;
        $this->createdOn    = $createdOn;
        $this->lastSeen     = $lastSeen;
        $this->active       = $active;
        $this->app          = $app;
        $this->isPhone      = $isPhone;
    }

    /**
     * @param array $row
     *
     * @return Device
     */
    public static function fromAssociativeArray($row)
    {
        $OStype     = new DeviceOStypeEnum($row['os_type']);
        $osVersion  = Version::fromString($row['os_version']);
        $createdOn  = dateTimeFromSQLquery($row['created_on']);
        $lastSeen   = dateTimeFromSQLquery($row['last_seen']);
        $active     = (bool) $row['active'];
        $deviceGuid = binaryGuidAsStringGuid($row['device_guid_bin']);
        $isPhone    = (bool) $row['is_phone'];
        $app        = AppDAO::applicationWithId($row['app_id']);
        return new Device(
            $row['id'] ,
            $deviceGuid ,
            $OStype ,
            $osVersion ,
            $row['manufacturer'] ,
            $row['model_code'] ,
            $createdOn ,
            $lastSeen ,
            $active ,
            $isPhone ,
            $app
        );

    }

// plus a whole bunch of business logic after

DeviceDAO (partiel) DeviceDAO(partiel)

namespace DAO;

use enums\DeviceOStypeEnum;
use NAO\Inbound\IBDeviceSpec;
use protocols\IClassInit;
use traits\ClassInitTrait;

class DeviceDAO implements IClassInit
{

    use ClassInitTrait;

    /**
     * @param string $guid
     * @param DeviceOStypeEnum $osType
     * @param Version $osVersion
     * @param string $manufacturer
     * @param string $modelCode
     * @param boolean $isPhone
     * @param App $app
     *
     * @return Device|null
     */
    public static function insert($guid ,
                                  DeviceOStypeEnum $osType , Version $osVersion ,
                                  $manufacturer , $modelCode ,
                                  $isPhone , App $app)
    {
        $pdo       = self::getClassPDO();
        $q         = $e = null;
        $createdOn = now();
        $lastSeen  = now();
        $sql       = <<<SQL
INSERT INTO Device SET device_guid_bin = :guid, 
os_type = :ost, 
os_version = :version ,
manufacturer=:manufacturer,model_code=:model,
created_on=:co, last_seen = :lastseen ,  active=1, `is_phone`=:phone, `app_id` = :appid

SQL;
        $device    = null;
        try {
            $q = $pdo->prepare($sql);
            $q->bindValue('guid' , stringGuidAsBinaryGuid($guid) , \PDO::PARAM_STR);
            $q->bindValue('ost' , $osType->stringValue , \PDO::PARAM_STR);
            $q->bindValue('version' , $osVersion->__toString() , \PDO::PARAM_STR);
            $q->bindValue('manufacturer' , $manufacturer , \PDO::PARAM_STR);
            $q->bindValue('model' , $modelCode , \PDO::PARAM_STR);
            $q->bindValue('co' , dateTimeAsSQLstring($createdOn) , \PDO::PARAM_STR);
            $q->bindValue('lastseen' , dateTimeAsSQLstring($lastSeen) , \PDO::PARAM_STR);
            $q->bindValue('phone' , $isPhone , \PDO::PARAM_BOOL);
            $q->bindValue('appid' , $app->getId() , \PDO::PARAM_INT);
            if ($q->execute()) {
                $id     = $pdo->lastInsertId();
                $device = new Device(
                    $id , $guid ,
                    $osType , $osVersion ,
                    $manufacturer , $modelCode ,
                    $createdOn , $lastSeen , true , $isPhone ,
                    $app
                );
            } else {
                self::logQueryFail("Unknown error while inserting a device" , $q , $e);
            }

        } catch (\Exception $e) {
            self::logQueryFail("Error while inserting a Device" , $q , $e);
        }
        return $device;

    }

    /**
     * @param IBDeviceSpec $spec
     *
     * @return Device|null
     */
    public static function insertWithDeviceSpec(IBDeviceSpec $spec)
    {
        $app = AppDAO::applicationWithGuid($spec->appGuid);
        return self::insert(
            $spec->deviceGuid , $spec->osType , $spec->osVersion , $spec->manufacturer , $spec->modelCode ,
            $spec->isPhone , $app
        );

    }

    /**
     * @param Device $device
     *
     * @return bool
     */
    public static function update(Device $device)
    {

        if (!$device) {
            self::getClassLogger()->error("Attemptempt to update null Device");
            return false;
        }
        $pdo = self::getClassPDO();
        $q   = $e = null;

        $sql = <<<SQL
UPDATE  Device 
SET device_guid_bin = :guid, 
os_type = :ost, 
os_version = :version ,
manufacturer=:manufacturer,
model_code=:model,
created_on=:co, 
last_seen = :lastseen,  
active=:ac,   
`is_phone`=:phone, 
`app_id`=:appid
WHERE 
id=:id

SQL;
        try {
            $q = $pdo->prepare($sql);
            $q->bindValue('id' , $device->getId() , \PDO::PARAM_STR);
            $q->bindValue('guid' , stringGuidAsBinaryGuid($device->deviceGuid) , \PDO::PARAM_STR);
            $q->bindValue('ost' , $device->osType->stringValue , \PDO::PARAM_STR);
            $q->bindValue('version' , $device->osVersion->__toString() , \PDO::PARAM_STR);
            $q->bindValue('manufacturer' , $device->manufacturer , \PDO::PARAM_STR);
            $q->bindValue('model' , $device->modelCode , \PDO::PARAM_STR);
            $q->bindValue('co' , dateTimeAsSQLstring($device->createdOn) , \PDO::PARAM_STR);
            $q->bindValue('lastseen' , dateTimeAsSQLstring($device->lastSeen) , \PDO::PARAM_STR);
            $q->bindValue('ac' , $device->active , \PDO::PARAM_BOOL);
            $q->bindValue('phone' , $device->isPhone , \PDO::PARAM_BOOL);
            $q->bindValue('appid' , $device->app->getId() , \PDO::PARAM_INT);
            if ($q->execute()) {
                return true;
            } else {
                self::logQueryFail("Unknown error while updating a device" , $q , $e);
            }

        } catch (\Exception $e) {
            self::logQueryFail("Error while inserting a Device" , $q , $e);
        }
        return false;

    }

    /**
     * @param string $guid
     *
     * @return Device|null
     */

    public static function deviceWithDeviceGuid($guid)
    {
        if (!$guid) return null;
        $pdo    = self::getClassPDO();
        $q      = $e = null;
        $device = null;

        $sql = <<<SQL
SELECT * FROM Device WHERE device_guid_bin=:gu  
SQL;
        try {

            $q = $pdo->prepare($sql);
            $q->bindValue(':gu' , stringGuidAsBinaryGuid($guid) , \PDO::PARAM_STR);
            if ($q->execute()) {
                $rows = $q->fetchAll();
                if (count($rows) == 0) {
                    self::getClassLogger()->trace(__FUNCTION__ . " Query for device [$guid] returned no device");
                } else if (count($rows) > 1) {
                    self::logQueryFail(__FUNCTION__ . " : Query for device returned multiple rows ! [$guid]" , $q , $e);
                } else {
                    $row    = $rows[0];
                    $device = Device::fromAssociativeArray($row);
                }
            } else {
                self::logQueryFail(__FUNCTION__ . " : Error while fetching device with guid[$guid]" , $q , $e);
            }
        } catch (\Exception $e) {
            self::logQueryFail(__FUNCTION__ . " : Error while fetching device with guid[$guid]" , $q , $e);
        }

        return $device;
    }

}
// etc ...

The SQL SQL

--
-- Table structure for table `Device` 
--

DROP TABLE IF EXISTS `Device`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `Device`
(
`id`              bigint(20)                               NOT NULL AUTO_INCREMENT,
`app_id`          bigint(20)                               NOT NULL,
`os_type`         enum ('android','iPhone OS','iOS','nix') NOT NULL,
`os_version`      varchar(11)                                       DEFAULT NULL,
`manufacturer`    varchar(50)                                       DEFAULT NULL,
`model_code`      varchar(50)                                       DEFAULT NULL,
`created_on`      datetime                                 NOT NULL,
`last_seen`       datetime                                 NOT NULL,
`active`          tinyint(4)                               NOT NULL DEFAULT '1',
`is_phone`        tinyint(4)                               NOT NULL DEFAULT '1',
`device_guid_bin` varbinary(16)                                     DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_device_guid` (`device_guid_bin`),
KEY `idx_app` (`app_id`),
KEY `idx_active` (`active`),
CONSTRAINT `fk_device_app` FOREIGN KEY (`app_id`) REFERENCES `App` (`id`) ON DELETE CASCADE
) ENGINE = InnoDB
  AUTO_INCREMENT = 68
  DEFAULT CHARSET = utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;

notes 笔记

  • Have not shown functions like dateTimeFromSQLquery etc ... all in my global functions. 在我的全局函数中没有显示出诸如dateTimeFromSQLquery等的函数。 I use such to normalize DB. 我用这样来规范化数据库。 Time is always UTC at rest (DB), and in flight (API) 时间始终是UTC静止(DB)和飞行(API)
  • For relationships, i systematically prefer a lazy load method (not in the code shown) 对于关系,我系统地倾向于使用惰性加载方法(不在所示代码中)
  • SomeObjectDAO encapsulates completely caching (or not). SomeObjectDAO封装(或不封装)完全缓存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM